use anyhow::Result;

use crate::state::context_env;
use crate::state::session as session_state;
use crate::state::work_stream_decay;

use super::{ContextHealth, ContextSignals};

pub(super) fn build_context_health(
    tracked_session: Option<&session_state::SessionStateFile>,
    work_stream_decay: &work_stream_decay::WorkStreamDecayView,
) -> Result<ContextHealth> {
    let now_epoch_s = session_state::now_epoch_s()?;
    let context_used_pct = context_env::optional_u8("CCD_CONTEXT_USED_PCT");
    let signals = ContextSignals {
        compacted: context_env::optional_bool("CCD_CONTEXT_COMPACTED"),
        session_minutes: tracked_session
            .map(|state| session_state::session_minutes(state, now_epoch_s)),
        ccd_start_cycles_in_conversation: tracked_session.map(|state| state.start_count),
        tool_output_kb: context_env::optional_u64("CCD_TOOL_OUTPUT_KB"),
        operator_symptoms: context_env::optional_list("CCD_OPERATOR_SYMPTOMS"),
    };
    let has_env_signal = context_used_pct.is_some()
        || signals.compacted.is_some()
        || signals.tool_output_kb.is_some()
        || !signals.operator_symptoms.is_empty();
    let has_session_signal =
        signals.session_minutes.is_some() || signals.ccd_start_cycles_in_conversation.is_some();
    let source = match (has_env_signal, has_session_signal) {
        (true, true) => "mixed",
        (true, false) => "env",
        (false, true) => "heuristic",
        (false, false) => "none",
    };

    let mut risk = 0u8;
    let mut scored_signals = 0usize;

    if let Some(minutes) = signals.session_minutes {
        scored_signals += 1;
        risk = risk.saturating_add(match minutes {
            0..=29 => 0,
            30..=59 => 10,
            60..=89 => 25,
            _ => 40,
        });
    }

    if let Some(cycles) = signals.ccd_start_cycles_in_conversation {
        scored_signals += 1;
        risk = risk.saturating_add(match cycles {
            0..=1 => 0,
            2..=3 => 10,
            _ => 25,
        });
    }

    if let Some(used_pct) = context_used_pct {
        scored_signals += 1;
        risk = risk.saturating_add(match used_pct {
            0..=69 => 0,
            70..=84 => 10,
            85..=94 => 20,
            _ => 30,
        });
    }

    if let Some(compacted) = signals.compacted {
        scored_signals += 1;
        if compacted {
            risk = risk.saturating_add(35);
        }
    }

    if let Some(tool_output_kb) = signals.tool_output_kb {
        scored_signals += 1;
        risk = risk.saturating_add(match tool_output_kb {
            0..=99 => 0,
            100..=249 => 10,
            250..=499 => 20,
            _ => 30,
        });
    }

    if !signals.operator_symptoms.is_empty() {
        scored_signals += 1;
        let symptom_score: u8 = signals.operator_symptoms.iter().take(3).map(|_| 15u8).sum();
        risk = risk.saturating_add(symptom_score);
    }

    if work_stream_decay.consecutive_no_progress > 0 {
        scored_signals += 1;
        risk = risk.saturating_add(match work_stream_decay.consecutive_no_progress {
            0..=1 => 5,
            2 => 20,
            _ => 35,
        });
    }

    let degradation_risk_pct = if scored_signals == 0 {
        None
    } else {
        Some(risk.min(95))
    };

    let band = match degradation_risk_pct {
        None => "unknown",
        Some(0..=34) => "low",
        Some(35..=59) => "moderate",
        Some(60..=79) => "risky",
        Some(_) => "critical",
    };

    let confidence = if signals.compacted.is_some() && has_session_signal {
        "high"
    } else if has_session_signal || has_env_signal {
        "medium"
    } else {
        "low"
    };

    let recommendation = match degradation_risk_pct {
        Some(80..=100) => "wrap_up_and_clear",
        Some(60..=79) => "wrap_up_soon",
        Some(35..=59) => "keep_focus",
        Some(_) => "continue",
        None if has_env_signal || has_session_signal => "continue",
        None => "capture_session_state",
    };
    let recommendation = match work_stream_decay.status.as_str() {
        "critical" => "wrap_up_and_clear",
        "warning" if recommendation == "continue" => "wrap_up_soon",
        _ => recommendation,
    };

    Ok(ContextHealth {
        source: source.to_owned(),
        context_used_pct,
        degradation_risk_pct,
        band: band.to_owned(),
        confidence: confidence.to_owned(),
        signals,
        recommendation: recommendation.to_owned(),
    })
}
