use std::{
    collections::BTreeMap,
    fs,
    path::{Path, PathBuf},
};

use crate::{contracts::StageResultEnvelope, workspace::WorkspacePaths};

const BLUEPRINT_APPROVAL_REPAIR_HANDLER_ID: &str = "evaluator_blueprint_approved_to_task";
const BLUEPRINT_APPROVAL_REPAIR_POLICY_ID: &str =
    "blueprint_approval_pre_mutation_effect_validation";
const BLUEPRINT_REPAIR_APPLY_HANDLER_ID: &str = "mechanic_blueprint_repair_apply";

const BLUEPRINT_REPAIR_CONTRACT_STATUS: &str = "action=apply_repaired_generated_task artifacts=blueprint_repair_decision,repaired_generated_task,mechanic_report repaired_artifact=repaired_generated_task";
const BLUEPRINT_REPLAY_CONFLICT_CLASSES_STATUS: &str = "candidate=blueprint_candidate_duplicate_conflict,blueprint_candidate_markdown_conflict approval=blueprint_evaluation_duplicate_conflict,blueprint_approved_packet_conflict,blueprint_approved_markdown_conflict,blueprint_task_duplicate,blueprint_promotion_duplicate_conflict";
const BLUEPRINT_INERT_ARTIFACT_GUARD_STATUS: &str =
    "repaired_blueprint_artifact.md ignored; mechanic_report.md evidence only";
const BLUEPRINT_RUNTIME_OWNERSHIP_BOUNDARY_STATUS: &str =
    "mechanic writes repair artifacts only; runtime owns queues and canonical Blueprint state";

#[derive(Debug, Clone)]
pub(crate) struct LatestRuntimeEffectStageResult {
    pub(crate) path: PathBuf,
    pub(crate) stage_result: StageResultEnvelope,
}

pub(crate) fn latest_runtime_effect_stage_result(
    paths: &WorkspacePaths,
    stage_result_path: Option<&str>,
) -> Option<LatestRuntimeEffectStageResult> {
    let raw_path = stage_result_path?;
    let path = resolve_workspace_or_absolute_path(paths, raw_path);
    let stage_result = load_stage_result(&path)?;
    let latest = latest_sibling_runtime_effect_stage_result(&path, &stage_result);
    if latest.is_some() {
        return latest;
    }
    (!runtime_effect_status_metadata_from_stage_result(&stage_result).is_empty())
        .then_some(LatestRuntimeEffectStageResult { path, stage_result })
}

pub(crate) fn runtime_effect_status_metadata_from_stage_result(
    stage_result: &StageResultEnvelope,
) -> BTreeMap<String, String> {
    let mut rendered = BTreeMap::new();
    for (status_key, metadata_key) in [
        (
            "latest_runtime_effect_handler_id",
            "runtime_effect_handler_id",
        ),
        ("latest_runtime_effect_decision", "runtime_effect_decision"),
        (
            "latest_runtime_effect_failure_class",
            "runtime_effect_failure_class",
        ),
        (
            "latest_runtime_effect_failure_message",
            "runtime_effect_failure_message",
        ),
        (
            "latest_runtime_effect_mutation_phase",
            "runtime_effect_mutation_phase",
        ),
        (
            "latest_runtime_effect_failure_policy_id",
            "runtime_effect_failure_policy_id",
        ),
        (
            "latest_runtime_effect_recovery_action",
            "runtime_effect_recovery_action",
        ),
        (
            "latest_runtime_effect_source_lifecycle_plan_id",
            "runtime_effect_source_lifecycle_plan_id",
        ),
        (
            "latest_runtime_effect_source_lifecycle_action",
            "runtime_effect_source_lifecycle_action",
        ),
    ] {
        if let Some(value) = stage_result
            .metadata
            .get(metadata_key)
            .and_then(serde_json::Value::as_str)
            .filter(|value| !value.is_empty())
        {
            rendered.insert(status_key.to_owned(), value.to_owned());
        }
    }
    rendered.extend(blueprint_repair_diagnostic_status_values(&rendered));
    rendered
}

pub(crate) fn is_blueprint_repair_apply_context(metadata: &BTreeMap<String, String>) -> bool {
    metadata
        .get("latest_runtime_effect_handler_id")
        .is_some_and(|value| value == BLUEPRINT_REPAIR_APPLY_HANDLER_ID)
        && metadata
            .get("latest_runtime_effect_decision")
            .is_some_and(|value| value == "request_complete_source")
}

pub(crate) fn is_blueprint_approval_repair_context(metadata: &BTreeMap<String, String>) -> bool {
    metadata
        .get("latest_runtime_effect_handler_id")
        .is_some_and(|value| value == BLUEPRINT_APPROVAL_REPAIR_HANDLER_ID)
        && metadata
            .get("latest_runtime_effect_decision")
            .is_some_and(|value| value == "request_block_source")
        && metadata
            .get("latest_runtime_effect_failure_class")
            .is_some_and(|value| {
                matches!(
                    value.as_str(),
                    "generated_task_invalid" | "generated_task_missing"
                )
            })
        && metadata
            .get("latest_runtime_effect_mutation_phase")
            .is_some_and(|value| value == "pre_mutation")
        && metadata
            .get("latest_runtime_effect_failure_policy_id")
            .is_some_and(|value| value == BLUEPRINT_APPROVAL_REPAIR_POLICY_ID)
        && metadata
            .get("latest_runtime_effect_recovery_action")
            .is_some_and(|value| value == "route_to_node")
}

fn blueprint_repair_diagnostic_status_values(
    runtime_effect_values: &BTreeMap<String, String>,
) -> BTreeMap<String, String> {
    if !is_blueprint_approval_repair_context(runtime_effect_values) {
        return BTreeMap::new();
    }
    let handler_id = runtime_effect_values
        .get("latest_runtime_effect_handler_id")
        .map(String::as_str)
        .unwrap_or("unknown");
    let failure_class = runtime_effect_values
        .get("latest_runtime_effect_failure_class")
        .map(String::as_str)
        .unwrap_or("unknown");
    let mutation_phase = runtime_effect_values
        .get("latest_runtime_effect_mutation_phase")
        .map(String::as_str)
        .unwrap_or("unknown");
    let policy_id = runtime_effect_values
        .get("latest_runtime_effect_failure_policy_id")
        .map(String::as_str)
        .unwrap_or("unknown");
    let recovery_action = runtime_effect_values
        .get("latest_runtime_effect_recovery_action")
        .map(String::as_str)
        .unwrap_or("unknown");

    BTreeMap::from([
        (
            "latest_blueprint_repair_context".to_owned(),
            format!(
                "failed_handler={handler_id} failure_class={failure_class} mutation_phase={mutation_phase} policy={policy_id} recovery_action={recovery_action}"
            ),
        ),
        (
            "latest_blueprint_repair_contract".to_owned(),
            BLUEPRINT_REPAIR_CONTRACT_STATUS.to_owned(),
        ),
        (
            "latest_blueprint_replay_conflict_classes".to_owned(),
            BLUEPRINT_REPLAY_CONFLICT_CLASSES_STATUS.to_owned(),
        ),
        (
            "latest_blueprint_inert_artifact_guard".to_owned(),
            BLUEPRINT_INERT_ARTIFACT_GUARD_STATUS.to_owned(),
        ),
        (
            "latest_blueprint_runtime_ownership_boundary".to_owned(),
            BLUEPRINT_RUNTIME_OWNERSHIP_BOUNDARY_STATUS.to_owned(),
        ),
    ])
}

fn latest_sibling_runtime_effect_stage_result(
    path: &Path,
    stage_result: &StageResultEnvelope,
) -> Option<LatestRuntimeEffectStageResult> {
    let parent = path.parent()?;
    if !parent.is_dir() {
        return None;
    }
    let current_sort_key = stage_result_sort_key(stage_result, path);
    let mut candidates = Vec::new();
    let entries = fs::read_dir(parent).ok()?;
    for entry in entries.flatten() {
        let sibling = entry.path();
        if !sibling.is_file()
            || sibling.extension().and_then(|value| value.to_str()) != Some("json")
        {
            continue;
        }
        let Some(sibling_stage_result) = load_stage_result(&sibling) else {
            continue;
        };
        let sort_key = stage_result_sort_key(&sibling_stage_result, &sibling);
        if sort_key > current_sort_key {
            continue;
        }
        let metadata = runtime_effect_status_metadata_from_stage_result(&sibling_stage_result);
        if metadata.is_empty() {
            continue;
        }
        candidates.push((
            sort_key,
            LatestRuntimeEffectStageResult {
                path: sibling,
                stage_result: sibling_stage_result,
            },
            metadata,
        ));
    }
    candidates.sort_by(|left, right| left.0.cmp(&right.0));
    let (_, latest, latest_metadata) = candidates.last()?;
    if is_blueprint_repair_apply_context(latest_metadata) {
        return latest_blueprint_approval_repair_context(&candidates);
    }
    Some(latest.clone())
}

fn latest_blueprint_approval_repair_context(
    candidates: &[(
        String,
        LatestRuntimeEffectStageResult,
        BTreeMap<String, String>,
    )],
) -> Option<LatestRuntimeEffectStageResult> {
    candidates
        .iter()
        .rev()
        .find(|(_, _, metadata)| is_blueprint_approval_repair_context(metadata))
        .map(|(_, candidate, _)| candidate.clone())
}

fn stage_result_sort_key(stage_result: &StageResultEnvelope, path: &Path) -> String {
    format!(
        "{}\0{}\0{}",
        stage_result.completed_at.as_str(),
        stage_result.started_at.as_str(),
        path.file_name()
            .and_then(|value| value.to_str())
            .unwrap_or_default()
    )
}

fn load_stage_result(path: &Path) -> Option<StageResultEnvelope> {
    fs::read_to_string(path)
        .ok()
        .and_then(|raw| StageResultEnvelope::from_json_str(&raw).ok())
}

fn resolve_workspace_or_absolute_path(paths: &WorkspacePaths, raw_path: &str) -> PathBuf {
    let path = PathBuf::from(raw_path);
    if path.is_absolute() {
        path
    } else {
        paths.root.join(path)
    }
}
