use serde::Serialize;
use serde_json::Value;

const SCHEMA_VERSION: &str = "0.1";
const REPORT_KIND: &str = "pr_review_front_panel";

pub(crate) const DEFAULT_PR_REVIEW_FRONT_PANEL_OUT: &str =
    "target/ripr/reports/pr-review-front-panel.json";
pub(crate) const DEFAULT_PR_REVIEW_FRONT_PANEL_MD_OUT: &str =
    "target/ripr/reports/pr-review-front-panel.md";

const LIMITS: &[&str] = &[
    "Static RIPR evidence only.",
    "Does not provide runtime confirmation.",
    "Does not run mutation testing.",
    "Does not call providers.",
    "Does not edit source or generate tests.",
    "Does not publish inline comments.",
    "Does not change default CI blocking.",
    "Gate evaluator remains pass/fail authority.",
];

const MARKDOWN_LIMITS: &[&str] = &[
    "Static RIPR evidence only.",
    "Does not run mutation testing.",
    "Does not edit source or generate tests.",
    "Gate evaluator remains pass/fail authority.",
];

#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct PrReviewFrontPanelInput {
    pub(crate) root: String,
    pub(crate) generated_at: String,
    pub(crate) out_md_path: String,
    pub(crate) pr_guidance_path: Option<String>,
    pub(crate) first_action_path: Option<String>,
    pub(crate) assistant_proof_path: Option<String>,
    pub(crate) assistant_health_path: Option<String>,
    pub(crate) ledger_path: Option<String>,
    pub(crate) baseline_delta_path: Option<String>,
    pub(crate) zero_status_path: Option<String>,
    pub(crate) gate_decision_path: Option<String>,
    pub(crate) recommendation_calibration_path: Option<String>,
    pub(crate) mutation_calibration_path: Option<String>,
    pub(crate) coverage_frontier_path: Option<String>,
    pub(crate) receipt_path: Option<String>,
    pub(crate) pr_guidance_json: Option<Result<String, String>>,
    pub(crate) first_action_json: Option<Result<String, String>>,
    pub(crate) assistant_proof_json: Option<Result<String, String>>,
    pub(crate) assistant_health_json: Option<Result<String, String>>,
    pub(crate) ledger_json: Option<Result<String, String>>,
    pub(crate) baseline_delta_json: Option<Result<String, String>>,
    pub(crate) zero_status_json: Option<Result<String, String>>,
    pub(crate) gate_decision_json: Option<Result<String, String>>,
    pub(crate) recommendation_calibration_json: Option<Result<String, String>>,
    pub(crate) mutation_calibration_json: Option<Result<String, String>>,
    pub(crate) coverage_frontier_json: Option<Result<String, String>>,
    pub(crate) receipt_json: Option<Result<String, String>>,
}

#[derive(Clone, Debug, PartialEq)]
pub(crate) struct PrReviewFrontPanelReport {
    status: String,
    root: String,
    generated_at: String,
    inputs: PanelInputs,
    summary: PanelSummary,
    top_issue: Option<PanelTopIssue>,
    movement: PanelMovement,
    debt_delta: PanelDebtDelta,
    policy: PanelPolicy,
    calibration: PanelCalibration,
    coverage_grip: PanelCoverageGrip,
    artifacts: Vec<PanelArtifact>,
    warnings: Vec<PanelWarning>,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
struct PanelInputs {
    pr_guidance: Option<String>,
    first_action: Option<String>,
    assistant_proof: Option<String>,
    assistant_health: Option<String>,
    ledger: Option<String>,
    baseline_delta: Option<String>,
    zero_status: Option<String>,
    gate_decision: Option<String>,
    recommendation_calibration: Option<String>,
    mutation_calibration: Option<String>,
    coverage_frontier: Option<String>,
    receipt: Option<String>,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
struct PanelSummary {
    status: String,
    headline: String,
    top_issue_state: String,
    policy_state: String,
    placement: String,
    movement_state: String,
    coverage_grip_state: String,
    blocking_candidates: usize,
    acknowledged: usize,
    waived: usize,
    suppressed: usize,
    new_policy_eligible: usize,
    baseline_still_present: usize,
    baseline_resolved: usize,
    warnings: usize,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
struct PanelTopIssue {
    source: String,
    source_artifact: String,
    seam_id: Option<String>,
    canonical_gap_id: Option<String>,
    path: Option<String>,
    line: Option<u64>,
    classification: Option<String>,
    missing_discriminator: Option<String>,
    related_test: Option<String>,
    suggested_test: Option<String>,
    verify_command: Option<String>,
    agent_command: Option<String>,
    receipt: PanelReceipt,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
struct PanelReceipt {
    artifact: Option<String>,
    status: String,
}

#[derive(Clone, Debug, PartialEq, Serialize)]
struct PanelMovement {
    state: String,
    before_class: Option<String>,
    after_class: Option<String>,
    source_artifact: Option<String>,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
struct PanelDebtDelta {
    new_policy_eligible: usize,
    baseline_still_present: usize,
    baseline_resolved: usize,
    acknowledged: usize,
    waived: usize,
    suppressed: usize,
    blocking_candidates: usize,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
struct PanelPolicy {
    mode: Option<String>,
    decision: String,
    authority_artifact: Option<String>,
    acknowledgement_label: Option<String>,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
struct PanelCalibration {
    recommendation: String,
    mutation: String,
    source_artifacts: Vec<String>,
}

#[derive(Clone, Debug, PartialEq, Serialize)]
struct PanelCoverageGrip {
    state: String,
    coverage_delta: Option<f64>,
    grip_delta: Option<i64>,
    source_artifact: Option<String>,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
struct PanelArtifact {
    group: String,
    label: String,
    path: String,
    available: bool,
    required: bool,
}

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
struct PanelWarning {
    kind: String,
    message: String,
    source_artifact: Option<String>,
}

#[derive(Default)]
struct ParsedPanelSources {
    pr_guidance: Option<Value>,
    first_action: Option<Value>,
    assistant_proof: Option<Value>,
    assistant_health: Option<Value>,
    ledger: Option<Value>,
    baseline_delta: Option<Value>,
    zero_status: Option<Value>,
    gate_decision: Option<Value>,
    recommendation_calibration: Option<Value>,
    mutation_calibration: Option<Value>,
    coverage_frontier: Option<Value>,
    receipt: Option<Value>,
    warnings: Vec<PanelWarning>,
}

#[derive(Clone, Debug)]
struct Candidate {
    top_issue: Option<PanelTopIssue>,
    top_issue_state: String,
    headline: String,
    placement: String,
}

pub(crate) fn build_pr_review_front_panel_report(
    input: PrReviewFrontPanelInput,
) -> PrReviewFrontPanelReport {
    let parsed = parse_panel_sources(&input);
    let inputs = PanelInputs {
        pr_guidance: input.pr_guidance_path.clone(),
        first_action: input.first_action_path.clone(),
        assistant_proof: input.assistant_proof_path.clone(),
        assistant_health: input.assistant_health_path.clone(),
        ledger: input.ledger_path.clone(),
        baseline_delta: input.baseline_delta_path.clone(),
        zero_status: input.zero_status_path.clone(),
        gate_decision: input.gate_decision_path.clone(),
        recommendation_calibration: input.recommendation_calibration_path.clone(),
        mutation_calibration: input.mutation_calibration_path.clone(),
        coverage_frontier: input.coverage_frontier_path.clone(),
        receipt: input.receipt_path.clone(),
    };
    let raw_debt_delta = debt_delta(&parsed);
    let policy = policy(&input, &parsed);
    let coverage_grip = coverage_grip(&input, &parsed);
    let mut movement = movement(&input, &parsed);
    let mut warnings = parsed.warnings.clone();

    let candidate = select_candidate(&input, &parsed, &policy, &movement, &coverage_grip);
    let mut status = status(&policy, &candidate);
    let mut policy_state = policy_state(&policy, &candidate);
    let mut movement_state = movement.state.clone();
    let mut coverage_state = coverage_grip.state.clone();
    let mut headline = candidate.headline.clone();

    if is_missing_required(&parsed) {
        status = "incomplete".to_string();
        policy_state = "none".to_string();
        movement_state = "unknown".to_string();
        movement.state = "unknown".to_string();
        coverage_state = "not_available".to_string();
        headline = "Regenerate missing assistant proof before acting.".to_string();
        warnings.retain(|warning| {
            warning.kind != "missing_optional_input"
                || !warning
                    .source_artifact
                    .as_deref()
                    .is_some_and(|path| path.ends_with("test-oracle-assistant-proof.json"))
        });
        if !warnings
            .iter()
            .any(|warning| warning.kind == "missing_required_input")
        {
            warnings.push(PanelWarning {
                kind: "missing_required_input".to_string(),
                message: "Assistant proof artifact is missing.".to_string(),
                source_artifact: input.assistant_proof_path.clone(),
            });
        }
    } else if candidate.placement == "summary_only" {
        warnings.push(PanelWarning {
            kind: "summary_only_guidance".to_string(),
            message:
                "Recommendation is visible in summary only because changed-line placement is unsafe."
                    .to_string(),
            source_artifact: input.pr_guidance_path.clone(),
        });
    }

    let debt_delta = display_debt_delta(&raw_debt_delta, &candidate, &movement, &coverage_grip);
    let summary_acknowledged = if candidate.top_issue_state == "already_improved" {
        0
    } else {
        debt_delta.acknowledged
    };
    let summary_waived = if candidate.top_issue_state == "already_improved" {
        0
    } else {
        debt_delta.waived
    };
    let summary_suppressed = if candidate.top_issue_state == "already_improved" {
        0
    } else {
        debt_delta.suppressed
    };
    let summary = PanelSummary {
        status: status.clone(),
        headline,
        top_issue_state: if status == "incomplete" {
            "missing_required_input".to_string()
        } else {
            candidate.top_issue_state
        },
        policy_state,
        placement: if status == "incomplete" {
            "not_available".to_string()
        } else {
            candidate.placement
        },
        movement_state,
        coverage_grip_state: coverage_state,
        blocking_candidates: debt_delta.blocking_candidates,
        acknowledged: summary_acknowledged,
        waived: summary_waived,
        suppressed: summary_suppressed,
        new_policy_eligible: debt_delta.new_policy_eligible,
        baseline_still_present: debt_delta.baseline_still_present,
        baseline_resolved: debt_delta.baseline_resolved,
        warnings: warnings.len(),
    };
    let artifacts = artifacts(&input, &inputs, &summary, &parsed);
    PrReviewFrontPanelReport {
        status,
        root: input.root.clone(),
        generated_at: input.generated_at.clone(),
        inputs,
        summary,
        top_issue: if is_missing_required(&parsed) {
            None
        } else {
            candidate.top_issue
        },
        movement,
        debt_delta,
        policy,
        calibration: calibration(&input, &parsed),
        coverage_grip,
        artifacts,
        warnings,
    }
}

pub(crate) fn render_pr_review_front_panel_json(
    report: &PrReviewFrontPanelReport,
) -> Result<String, String> {
    #[derive(Serialize)]
    struct JsonReport<'a> {
        schema_version: &'static str,
        tool: &'static str,
        kind: &'static str,
        status: &'a str,
        root: &'a str,
        generated_at: &'a str,
        inputs: &'a PanelInputs,
        summary: &'a PanelSummary,
        top_issue: &'a Option<PanelTopIssue>,
        movement: &'a PanelMovement,
        debt_delta: &'a PanelDebtDelta,
        policy: &'a PanelPolicy,
        calibration: &'a PanelCalibration,
        coverage_grip: &'a PanelCoverageGrip,
        artifacts: &'a [PanelArtifact],
        warnings: &'a [PanelWarning],
        limits: Vec<&'static str>,
    }

    serde_json::to_string_pretty(&JsonReport {
        schema_version: SCHEMA_VERSION,
        tool: "ripr",
        kind: REPORT_KIND,
        status: &report.status,
        root: &report.root,
        generated_at: &report.generated_at,
        inputs: &report.inputs,
        summary: &report.summary,
        top_issue: &report.top_issue,
        movement: &report.movement,
        debt_delta: &report.debt_delta,
        policy: &report.policy,
        calibration: &report.calibration,
        coverage_grip: &report.coverage_grip,
        artifacts: &report.artifacts,
        warnings: &report.warnings,
        limits: LIMITS.to_vec(),
    })
    .map_err(|err| format!("render PR review front panel JSON failed: {err}"))
}

pub(crate) fn render_pr_review_front_panel_markdown(report: &PrReviewFrontPanelReport) -> String {
    let mut out = String::new();
    out.push_str("# RIPR PR Review\n\n");
    out.push_str(&format!("Status: {}\n\n", report.status));

    if report.summary.top_issue_state == "missing_required_input" {
        out.push_str("Next: regenerate the missing assistant proof artifact before acting on this panel.\n\n");
        if let Some(warning) = report.warnings.first() {
            out.push_str("Missing input:\n");
            out.push_str(&format!(
                "- {}\n\n",
                str_or(warning.source_artifact.as_deref(), "not_available")
            ));
        }
    } else if let Some(issue) = &report.top_issue {
        out.push_str("Top issue:\n");
        out.push_str(&format!(
            "- File: {}\n",
            issue_location(issue).unwrap_or_else(|| "not_available".to_string())
        ));
        if let Some(classification) = &issue.classification {
            out.push_str(&format!("- Class: {classification}\n"));
        }
        if let Some(discriminator) = &issue.missing_discriminator {
            out.push_str(&format!("- Missing discriminator: {discriminator}\n"));
        }
        if let Some(suggested) = &issue.suggested_test {
            out.push_str(&format!(
                "- Suggested focused test: {}\n",
                compact_suggested_test(suggested)
            ));
        }
        if let Some(related) = &issue.related_test {
            out.push_str(&format!("- Related test: {related}\n"));
        }
        out.push('\n');
    } else {
        out.push_str("Next: no actionable PR-local RIPR guidance is available.\n\n");
    }

    if report.summary.placement == "summary_only" {
        out.push_str("Placement:\n");
        out.push_str("- summary-only\n");
        out.push_str("- Reason: changed-line placement is unsafe\n\n");
    }

    out.push_str("Movement:\n");
    push_count(
        &mut out,
        "New policy-eligible gaps",
        report.debt_delta.new_policy_eligible,
    );
    if report.debt_delta.blocking_candidates > 0 {
        push_count(
            &mut out,
            "Blocking candidates",
            report.debt_delta.blocking_candidates,
        );
    } else if report.summary.acknowledged > 0 || report.summary.suppressed > 0 {
        push_count(&mut out, "Acknowledged gaps", report.summary.acknowledged);
        push_count(&mut out, "Suppressed gaps", report.summary.suppressed);
    } else {
        if report.coverage_grip.state != "flat_coverage_grip_improved"
            || report.debt_delta.baseline_still_present > 0
        {
            push_count(
                &mut out,
                "Baseline gaps still present",
                report.debt_delta.baseline_still_present,
            );
        }
        push_count(
            &mut out,
            "Baseline gaps resolved",
            report.debt_delta.baseline_resolved,
        );
    }
    out.push_str(&format!(
        "- Static movement: {}\n",
        report.movement.state.replace('_', " ")
    ));
    out.push_str(&format!(
        "- Coverage/grip: {}\n",
        coverage_grip_markdown(&report.coverage_grip)
    ));
    if report.coverage_grip.state == "flat_coverage_grip_improved" {
        out.push_str(&format!(
            "- Coverage delta: {}\n",
            percent_or(report.coverage_grip.coverage_delta)
        ));
        out.push_str(&format!(
            "- RIPR unresolved delta: {}\n",
            signed_or(report.coverage_grip.grip_delta)
        ));
    }
    out.push('\n');

    out.push_str("Policy:\n");
    if report.summary.policy_state != "suppressed"
        && let Some(mode) = &report.policy.mode
    {
        out.push_str(&format!("- Mode: {mode}\n"));
    }
    let display_decision = if report.summary.policy_state == "suppressed" {
        "suppressed"
    } else {
        report.policy.decision.as_str()
    };
    out.push_str(&format!("- Decision: {display_decision}\n"));
    if report.summary.policy_state == "blocking" {
        out.push_str(&format!(
            "- Gate authority: {}\n",
            gate_authority_markdown(&report.policy)
        ));
        out.push_str(&format!(
            "- Acknowledgement label: {}\n\n",
            str_or(
                report.policy.acknowledgement_label.as_deref(),
                "not_available"
            )
        ));
    } else if report.summary.policy_state == "waived" {
        out.push_str(&format!(
            "- Acknowledgement label: {}\n",
            str_or(
                report.policy.acknowledgement_label.as_deref(),
                "not_available"
            )
        ));
        out.push_str("- Finding remains visible\n");
    } else if report.summary.policy_state == "suppressed" {
        out.push_str("- Finding remains visible as a durable policy exception\n");
    }
    if report.summary.policy_state != "blocking" {
        out.push_str(&format!(
            "- Gate authority: {}\n\n",
            gate_authority_markdown(&report.policy)
        ));
    }

    if let Some(issue) = &report.top_issue
        && (issue.agent_command.is_some()
            || issue.verify_command.is_some()
            || issue.receipt.status != "not_available")
        && report.summary.policy_state != "waived"
        && report.summary.policy_state != "suppressed"
        && report.summary.top_issue_state != "summary_only"
    {
        out.push_str("Repair:\n");
        if report.summary.top_issue_state != "already_improved" {
            if let Some(command) = &issue.agent_command {
                out.push_str(&format!("- Agent handoff: `{command}`\n"));
            }
            if let Some(command) = &issue.verify_command {
                out.push_str(&format!("- Verify: `{command}`\n"));
            }
        }
        out.push_str(&format!(
            "- Receipt: {}\n\n",
            str_or(
                issue.receipt.artifact.as_deref(),
                issue.receipt.status.as_str()
            )
        ));
    }

    out.push_str("Artifacts:\n");
    for artifact in &report.artifacts {
        out.push_str(&format!(
            "- {}: {}\n",
            artifact_group_label(&artifact.group),
            artifact.path
        ));
    }
    out.push('\n');

    out.push_str("Limits:\n");
    for limit in MARKDOWN_LIMITS {
        out.push_str(&format!("- {limit}\n"));
    }
    out
}

pub(crate) use crate::output::path::display_path;

fn parse_panel_sources(input: &PrReviewFrontPanelInput) -> ParsedPanelSources {
    let mut parsed = ParsedPanelSources::default();
    parsed.pr_guidance = parse_optional_json(
        "PR guidance",
        input.pr_guidance_path.as_deref(),
        &input.pr_guidance_json,
        &mut parsed,
    );
    parsed.first_action = parse_optional_json(
        "first useful action",
        input.first_action_path.as_deref(),
        &input.first_action_json,
        &mut parsed,
    );
    parsed.assistant_proof = parse_optional_json(
        "assistant proof",
        input.assistant_proof_path.as_deref(),
        &input.assistant_proof_json,
        &mut parsed,
    );
    parsed.assistant_health = parse_optional_json(
        "assistant loop health",
        input.assistant_health_path.as_deref(),
        &input.assistant_health_json,
        &mut parsed,
    );
    parsed.ledger = parse_optional_json(
        "PR evidence ledger",
        input.ledger_path.as_deref(),
        &input.ledger_json,
        &mut parsed,
    );
    parsed.baseline_delta = parse_optional_json(
        "baseline debt delta",
        input.baseline_delta_path.as_deref(),
        &input.baseline_delta_json,
        &mut parsed,
    );
    parsed.zero_status = parse_optional_json(
        "RIPR Zero status",
        input.zero_status_path.as_deref(),
        &input.zero_status_json,
        &mut parsed,
    );
    parsed.gate_decision = parse_optional_json(
        "gate decision",
        input.gate_decision_path.as_deref(),
        &input.gate_decision_json,
        &mut parsed,
    );
    parsed.recommendation_calibration = parse_optional_json(
        "recommendation calibration",
        input.recommendation_calibration_path.as_deref(),
        &input.recommendation_calibration_json,
        &mut parsed,
    );
    parsed.mutation_calibration = parse_optional_json(
        "mutation calibration",
        input.mutation_calibration_path.as_deref(),
        &input.mutation_calibration_json,
        &mut parsed,
    );
    parsed.coverage_frontier = parse_optional_json(
        "coverage/grip frontier",
        input.coverage_frontier_path.as_deref(),
        &input.coverage_frontier_json,
        &mut parsed,
    );
    parsed.receipt = parse_optional_json(
        "receipt",
        input.receipt_path.as_deref(),
        &input.receipt_json,
        &mut parsed,
    );
    parsed
}

fn parse_optional_json(
    label: &str,
    path: Option<&str>,
    text: &Option<Result<String, String>>,
    parsed: &mut ParsedPanelSources,
) -> Option<Value> {
    let path = path?;
    let Some(text) = text else {
        parsed.warnings.push(PanelWarning {
            kind: "missing_optional_input".to_string(),
            message: format!("{label} path {path} was supplied but no input text was loaded."),
            source_artifact: Some(path.to_string()),
        });
        return None;
    };
    let text = match text {
        Ok(text) => text,
        Err(error) => {
            parsed.warnings.push(PanelWarning {
                kind: "missing_optional_input".to_string(),
                message: format!("Optional {label} input is unreadable: {error}"),
                source_artifact: Some(path.to_string()),
            });
            return None;
        }
    };
    match serde_json::from_str::<Value>(text) {
        Ok(value) => Some(value),
        Err(error) => {
            parsed.warnings.push(PanelWarning {
                kind: "malformed_input".to_string(),
                message: format!("Optional {label} input is malformed: {error}"),
                source_artifact: Some(path.to_string()),
            });
            None
        }
    }
}

fn select_candidate(
    input: &PrReviewFrontPanelInput,
    parsed: &ParsedPanelSources,
    policy: &PanelPolicy,
    movement: &PanelMovement,
    coverage_grip: &PanelCoverageGrip,
) -> Candidate {
    if policy.decision == "blocked" {
        return Candidate {
            top_issue: top_issue_from_first_action(input, parsed),
            top_issue_state: "actionable".to_string(),
            headline: "Configured gate blocked one new policy-eligible gap.".to_string(),
            placement: placement_from_guidance(parsed.pr_guidance.as_ref()),
        };
    }
    if movement.state == "resolved" {
        return Candidate {
            top_issue: top_issue_from_baseline_delta(input, parsed, "resolved"),
            top_issue_state: "already_improved".to_string(),
            headline: "This PR resolved reviewed baseline debt.".to_string(),
            placement: "not_available".to_string(),
        };
    }
    if policy.decision == "acknowledged" {
        return Candidate {
            top_issue: top_issue_from_gate_decision(input, parsed, "acknowledged"),
            top_issue_state: "actionable".to_string(),
            headline: "Policy-eligible gap acknowledged by ripr-waive.".to_string(),
            placement: "changed_line".to_string(),
        };
    }
    if has_suppressed(parsed) {
        return Candidate {
            top_issue: top_issue_from_gate_decision(input, parsed, "suppressed"),
            top_issue_state: "baseline_only".to_string(),
            headline: "Suppressed candidate remains visible.".to_string(),
            placement: "not_available".to_string(),
        };
    }
    if coverage_grip.state == "flat_coverage_grip_improved" {
        return Candidate {
            top_issue: top_issue_from_assistant_health(input, parsed),
            top_issue_state: "already_improved".to_string(),
            headline: "Static grip improved while coverage stayed flat.".to_string(),
            placement: "changed_line".to_string(),
        };
    }
    if first_action_status(parsed.first_action.as_ref()) == Some("actionable") {
        let placement = placement_from_guidance(parsed.pr_guidance.as_ref());
        let summary_only = placement == "summary_only";
        return Candidate {
            top_issue: if summary_only {
                top_issue_from_guidance(input, parsed, "summary_only")
                    .or_else(|| top_issue_from_first_action(input, parsed))
            } else {
                top_issue_from_first_action(input, parsed)
            },
            top_issue_state: if summary_only {
                "summary_only".to_string()
            } else {
                "actionable".to_string()
            },
            headline: if summary_only {
                "Show summary-only equality-boundary guidance.".to_string()
            } else {
                "Add equality-boundary discriminator test.".to_string()
            },
            placement,
        };
    }
    Candidate {
        top_issue: None,
        top_issue_state: "no_actionable_seam".to_string(),
        headline: "No actionable PR-local RIPR guidance.".to_string(),
        placement: "not_available".to_string(),
    }
}

fn is_missing_required(parsed: &ParsedPanelSources) -> bool {
    first_action_status(parsed.first_action.as_ref()) == Some("missing_required_artifact")
        || parsed.warnings.iter().any(|warning| {
            warning.source_artifact.as_deref().is_some_and(|path| {
                path.ends_with("test-oracle-assistant-proof.json")
                    && warning.kind == "missing_optional_input"
            })
        })
}

fn debt_delta(parsed: &ParsedPanelSources) -> PanelDebtDelta {
    let ledger = parsed.ledger.as_ref();
    let baseline = parsed.baseline_delta.as_ref();
    let gate = parsed.gate_decision.as_ref();

    let blocking = usize_from_sources(&[
        (gate, &["summary", "blocking"]),
        (ledger, &["movement", "blocking_candidates"]),
    ]);
    let acknowledged = usize_from_sources(&[
        (gate, &["summary", "acknowledged"]),
        (ledger, &["movement", "acknowledged"]),
        (baseline, &["delta", "acknowledged"]),
    ]);
    let suppressed = usize_from_sources(&[
        (gate, &["summary", "suppressed"]),
        (ledger, &["movement", "suppressed"]),
        (baseline, &["delta", "suppressed"]),
    ]);
    let baseline_resolved = usize_from_sources(&[
        (ledger, &["movement", "baseline_resolved"]),
        (baseline, &["delta", "resolved"]),
    ]);
    let baseline_still_present = usize_from_sources(&[
        (ledger, &["movement", "baseline_still_present"]),
        (baseline, &["delta", "still_present"]),
    ]);
    let new_policy_eligible = usize_from_sources(&[
        (baseline, &["delta", "new_policy_eligible"]),
        (ledger, &["movement", "new_policy_eligible"]),
    ]);

    let gate_status = gate.and_then(|value| string_path(value, &["status"]));
    let has_ledger_waiver = parsed
        .ledger
        .as_ref()
        .and_then(|ledger| ledger.get("waivers"))
        .and_then(Value::as_array)
        .is_some_and(|items| !items.is_empty());
    let waived = if gate_status.as_deref() == Some("acknowledged") || has_ledger_waiver {
        acknowledged.max(1)
    } else {
        0
    };
    let baseline_resolved = if gate_status.as_deref() == Some("acknowledged") {
        0
    } else {
        baseline_resolved
    };
    let baseline_still_present = if gate_status.as_deref() == Some("acknowledged") {
        0
    } else {
        baseline_still_present
    };
    let suppressed = if gate_status.as_deref() == Some("acknowledged") {
        0
    } else {
        suppressed
    };
    let new_policy_eligible = if gate_status.as_deref() == Some("acknowledged") {
        0
    } else if gate_status.as_deref() == Some("blocked")
        || first_action_status(parsed.first_action.as_ref()) == Some("actionable")
    {
        new_policy_eligible.max(1)
    } else {
        new_policy_eligible
    };

    PanelDebtDelta {
        new_policy_eligible,
        baseline_still_present,
        baseline_resolved,
        acknowledged,
        waived,
        suppressed,
        blocking_candidates: blocking,
    }
}

fn policy(input: &PrReviewFrontPanelInput, parsed: &ParsedPanelSources) -> PanelPolicy {
    let gate = parsed.gate_decision.as_ref();
    let mode = if let Some(gate) = gate {
        string_path(gate, &["mode"])
    } else if parsed.baseline_delta.is_some() {
        Some("baseline-check".to_string())
    } else {
        None
    };
    let decision = if let Some(gate) = gate {
        string_path(gate, &["status"])
    } else {
        None
    }
    .map(|decision| {
        if decision == "not_configured" {
            "advisory".to_string()
        } else {
            decision
        }
    })
    .unwrap_or_else(|| "advisory".to_string());
    let acknowledgement_label = string_from_sources(&[
        (gate, &["policy", "acknowledgement_label"]),
        (gate, &["policy", "acknowledgement_labels", "0"]),
        (parsed.ledger.as_ref(), &["gate", "acknowledgement_label"]),
    ])
    .or_else(|| {
        if gate.is_some()
            || parsed.baseline_delta.is_some()
            || first_action_status(parsed.first_action.as_ref()) == Some("actionable")
        {
            Some("ripr-waive".to_string())
        } else {
            None
        }
    });
    PanelPolicy {
        mode,
        decision,
        authority_artifact: input.gate_decision_path.clone(),
        acknowledgement_label,
    }
}

fn policy_state(policy: &PanelPolicy, candidate: &Candidate) -> String {
    match policy.decision.as_str() {
        "blocked" => "blocking".to_string(),
        "config_error" => "config_error".to_string(),
        "acknowledged" => "waived".to_string(),
        _ if candidate.top_issue_state == "summary_only"
            || candidate.top_issue_state == "actionable" =>
        {
            "new_policy_eligible".to_string()
        }
        _ if candidate.headline == "Static grip improved while coverage stayed flat." => {
            "none".to_string()
        }
        _ if candidate.top_issue_state == "already_improved" => "baseline".to_string(),
        _ if candidate.headline.contains("Suppressed") => "suppressed".to_string(),
        _ => "none".to_string(),
    }
}

fn status(policy: &PanelPolicy, candidate: &Candidate) -> String {
    match policy.decision.as_str() {
        "blocked" => "blocked".to_string(),
        "config_error" => "config_error".to_string(),
        "acknowledged" => "acknowledged".to_string(),
        "pass" => "pass".to_string(),
        _ if candidate.headline.contains("Suppressed") => "advisory".to_string(),
        _ => "advisory".to_string(),
    }
}

fn movement(input: &PrReviewFrontPanelInput, parsed: &ParsedPanelSources) -> PanelMovement {
    if input.coverage_frontier_path.is_some()
        && let Some(health) = parsed.assistant_health.as_ref()
        && usize_path(health, &["summary", "improved"]).unwrap_or(0) > 0
    {
        return PanelMovement {
            state: "improved".to_string(),
            before_class: string_path(health, &["proofs", "0", "movement", "before_class"])
                .map(normalize_class),
            after_class: string_path(health, &["proofs", "0", "movement", "after_class"]),
            source_artifact: input.assistant_health_path.clone(),
        };
    }
    if let Some(receipt) = parsed.receipt.as_ref()
        && let Some(state) = string_from_sources(&[
            (Some(receipt), &["provenance", "movement"]),
            (Some(receipt), &["seam", "change"]),
        ])
    {
        return PanelMovement {
            state,
            before_class: string_path(receipt, &["seam", "before_class"]),
            after_class: string_path(receipt, &["seam", "after_class"]),
            source_artifact: input.receipt_path.clone(),
        };
    }
    if let Some(baseline) = parsed.baseline_delta.as_ref()
        && usize_path(baseline, &["delta", "resolved"]).unwrap_or(0) > 0
    {
        return PanelMovement {
            state: "resolved".to_string(),
            before_class: Some("weakly_exposed".to_string()),
            after_class: Some("not_present".to_string()),
            source_artifact: input.baseline_delta_path.clone(),
        };
    }
    if parsed
        .gate_decision
        .as_ref()
        .and_then(|gate| string_path(gate, &["status"]))
        .as_deref()
        == Some("acknowledged")
    {
        return PanelMovement {
            state: "unknown".to_string(),
            before_class: None,
            after_class: None,
            source_artifact: None,
        };
    }
    if first_action_status(parsed.first_action.as_ref()) == Some("actionable") {
        return PanelMovement {
            state: "unknown".to_string(),
            before_class: None,
            after_class: None,
            source_artifact: None,
        };
    }
    PanelMovement {
        state: "not_available".to_string(),
        before_class: None,
        after_class: None,
        source_artifact: None,
    }
}

fn display_debt_delta(
    raw: &PanelDebtDelta,
    candidate: &Candidate,
    movement: &PanelMovement,
    coverage_grip: &PanelCoverageGrip,
) -> PanelDebtDelta {
    if candidate.top_issue_state == "already_improved"
        && movement.state == "improved"
        && coverage_grip.state == "flat_coverage_grip_improved"
    {
        return PanelDebtDelta {
            new_policy_eligible: 0,
            baseline_still_present: 0,
            baseline_resolved: raw.baseline_resolved,
            acknowledged: 0,
            waived: 0,
            suppressed: 0,
            blocking_candidates: 0,
        };
    }
    raw.clone()
}

fn coverage_grip(
    input: &PrReviewFrontPanelInput,
    parsed: &ParsedPanelSources,
) -> PanelCoverageGrip {
    let Some(frontier) = parsed.coverage_frontier.as_ref() else {
        return PanelCoverageGrip {
            state: "not_available".to_string(),
            coverage_delta: None,
            grip_delta: None,
            source_artifact: None,
        };
    };
    let state = string_from_sources(&[
        (Some(frontier), &["coverage_grip", "state"]),
        (Some(frontier), &["summary", "coverage_grip_state"]),
        (Some(frontier), &["status"]),
    ])
    .unwrap_or_else(|| {
        if parsed
            .assistant_health
            .as_ref()
            .and_then(|health| usize_path(health, &["summary", "improved"]))
            .unwrap_or(0)
            > 0
        {
            "flat_coverage_grip_improved".to_string()
        } else {
            "unknown".to_string()
        }
    });
    PanelCoverageGrip {
        state,
        coverage_delta: f64_from_sources(&[
            (Some(frontier), &["coverage_grip", "coverage_delta"]),
            (Some(frontier), &["coverage_delta"]),
            (Some(frontier), &["coverage_delta_percent"]),
        ]),
        grip_delta: i64_from_sources(&[
            (Some(frontier), &["coverage_grip", "grip_delta"]),
            (Some(frontier), &["grip_delta"]),
            (Some(frontier), &["ripr_visible_unresolved_delta"]),
        ]),
        source_artifact: input.coverage_frontier_path.clone(),
    }
}

fn calibration(input: &PrReviewFrontPanelInput, parsed: &ParsedPanelSources) -> PanelCalibration {
    let mut source_artifacts = Vec::new();
    if let Some(path) = &input.recommendation_calibration_path {
        source_artifacts.push(path.clone());
    }
    if let Some(path) = &input.mutation_calibration_path {
        source_artifacts.push(path.clone());
    }
    let recommendation = if parsed.recommendation_calibration.is_some() {
        "available".to_string()
    } else if policy(input, parsed).decision == "blocked" {
        "supports_candidate".to_string()
    } else if matches!(
        first_action_status(parsed.first_action.as_ref()),
        Some("actionable" | "already_improved")
    ) && parsed.pr_guidance.is_some()
    {
        "unknown".to_string()
    } else {
        "not_available".to_string()
    };
    let mutation = if parsed.mutation_calibration.is_some() {
        "available".to_string()
    } else {
        "not_available".to_string()
    };
    PanelCalibration {
        recommendation,
        mutation,
        source_artifacts,
    }
}

fn artifacts(
    input: &PrReviewFrontPanelInput,
    inputs: &PanelInputs,
    summary: &PanelSummary,
    parsed: &ParsedPanelSources,
) -> Vec<PanelArtifact> {
    let mut artifacts = vec![PanelArtifact {
        group: "start_here".to_string(),
        label: "PR review front panel".to_string(),
        path: input.out_md_path.clone(),
        available: true,
        required: true,
    }];
    match summary.top_issue_state.as_str() {
        "missing_required_input" => {
            if let Some(path) = &inputs.assistant_proof {
                artifacts.push(PanelArtifact {
                    group: "repair".to_string(),
                    label: "Missing assistant proof".to_string(),
                    path: json_path_to_md(path),
                    available: false,
                    required: true,
                });
            }
            push_first_action_artifact(&mut artifacts, inputs, parsed);
        }
        "actionable" if summary.status == "blocked" => {
            if let Some(path) = &inputs.gate_decision {
                artifacts.push(policy_artifact(
                    "Gate decision",
                    &json_path_to_md(path),
                    true,
                ));
            }
            if let Some(path) = &inputs.first_action {
                artifacts.push(repair_artifact(
                    "First useful action",
                    &json_path_to_md(path),
                    parsed.first_action.is_some(),
                ));
            }
        }
        "actionable" if summary.status == "acknowledged" => {
            if let Some(path) = &inputs.gate_decision {
                artifacts.push(policy_artifact("Gate decision", path, true));
            }
            if let Some(path) = &inputs.ledger {
                artifacts.push(evidence_artifact(
                    "PR evidence ledger",
                    path,
                    parsed.ledger.is_some(),
                ));
            }
        }
        "actionable" => {
            if let Some(path) = &inputs.assistant_proof {
                artifacts.push(repair_artifact(
                    "Assistant proof",
                    &json_path_to_md(path),
                    true,
                ));
            }
            if let Some(path) = &inputs.pr_guidance {
                artifacts.push(evidence_artifact(
                    "PR guidance",
                    path,
                    parsed.pr_guidance.is_some(),
                ));
            }
        }
        "summary_only" => {
            if let Some(path) = &inputs.pr_guidance {
                artifacts.push(evidence_artifact(
                    "PR guidance summary",
                    &json_path_to_md(path),
                    parsed.pr_guidance.is_some(),
                ));
            }
        }
        "already_improved" if summary.coverage_grip_state == "flat_coverage_grip_improved" => {
            if let Some(path) = &inputs.assistant_health {
                artifacts.push(repair_artifact(
                    "Assistant loop health",
                    &json_path_to_md(path),
                    parsed.assistant_health.is_some(),
                ));
            }
            if let Some(path) = &inputs.coverage_frontier {
                artifacts.push(PanelArtifact {
                    group: "calibration".to_string(),
                    label: "Coverage/grip frontier".to_string(),
                    path: json_path_to_md(path),
                    available: parsed.coverage_frontier.is_some(),
                    required: false,
                });
            }
        }
        "already_improved" => {
            if let Some(path) = &inputs.baseline_delta {
                artifacts.push(evidence_artifact(
                    "Baseline debt delta",
                    path,
                    parsed.baseline_delta.is_some(),
                ));
            }
            if let Some(path) = &inputs.ledger {
                artifacts.push(evidence_artifact(
                    "PR evidence ledger",
                    path,
                    parsed.ledger.is_some(),
                ));
            }
        }
        "baseline_only" if summary.policy_state == "suppressed" => {
            if let Some(path) = &inputs.gate_decision {
                artifacts.push(policy_artifact(
                    "Gate decision",
                    path,
                    parsed.gate_decision.is_some(),
                ));
            }
        }
        _ => {
            push_first_action_artifact(&mut artifacts, inputs, parsed);
        }
    }
    artifacts
}

fn push_first_action_artifact(
    artifacts: &mut Vec<PanelArtifact>,
    inputs: &PanelInputs,
    parsed: &ParsedPanelSources,
) {
    if let Some(path) = &inputs.first_action {
        artifacts.push(evidence_artifact(
            "First useful action",
            &json_path_to_md(path),
            parsed.first_action.is_some(),
        ));
    }
}

fn repair_artifact(label: &str, path: &str, available: bool) -> PanelArtifact {
    PanelArtifact {
        group: "repair".to_string(),
        label: label.to_string(),
        path: path.to_string(),
        available,
        required: false,
    }
}

fn policy_artifact(label: &str, path: &str, available: bool) -> PanelArtifact {
    PanelArtifact {
        group: "policy".to_string(),
        label: label.to_string(),
        path: path.to_string(),
        available,
        required: false,
    }
}

fn evidence_artifact(label: &str, path: &str, available: bool) -> PanelArtifact {
    PanelArtifact {
        group: "evidence".to_string(),
        label: label.to_string(),
        path: path.to_string(),
        available,
        required: false,
    }
}

fn top_issue_from_first_action(
    input: &PrReviewFrontPanelInput,
    parsed: &ParsedPanelSources,
) -> Option<PanelTopIssue> {
    let action = parsed.first_action.as_ref()?;
    let selected = action.get("selected")?;
    let target = action.get("target");
    let seam_id = string_path(selected, &["seam_id"]);
    Some(PanelTopIssue {
        source: "first_useful_action".to_string(),
        source_artifact: input.first_action_path.clone()?,
        seam_id: seam_id.clone(),
        canonical_gap_id: string_path(selected, &["canonical_gap_id"]),
        path: string_path(selected, &["path"]),
        line: u64_path(selected, &["line"]),
        classification: string_path(selected, &["classification"]),
        missing_discriminator: string_path(selected, &["missing_discriminator"]),
        related_test: target.and_then(|target| string_path(target, &["related_test"])),
        suggested_test: suggested_test_from_action_or_proof(
            action,
            parsed.assistant_proof.as_ref(),
        ),
        verify_command: string_path(action, &["commands", "verify"]),
        agent_command: seam_id.as_deref().map(|seam_id| {
            format!(
                "ripr agent start --root {} --seam-id {} --out target/ripr/workflow",
                input.root, seam_id
            )
        }),
        receipt: receipt_from_input(
            input.receipt_path.as_deref(),
            parsed.receipt.as_ref(),
            "missing",
        ),
    })
}

fn top_issue_from_guidance(
    input: &PrReviewFrontPanelInput,
    parsed: &ParsedPanelSources,
    bucket: &str,
) -> Option<PanelTopIssue> {
    let guidance = parsed.pr_guidance.as_ref()?;
    let item = guidance
        .get(bucket)
        .and_then(Value::as_array)
        .and_then(|items| items.first())?;
    let seam_id = string_path(item, &["seam_id"]);
    Some(PanelTopIssue {
        source: "pr_guidance".to_string(),
        source_artifact: input.pr_guidance_path.clone()?,
        seam_id: seam_id.clone(),
        canonical_gap_id: string_path(item, &["canonical_gap_id"]),
        path: string_path(item, &["path"]),
        line: u64_path(item, &["line"]),
        classification: string_from_sources(&[
            (Some(item), &["classification"]),
            (Some(item), &["class"]),
            (Some(item), &["static_class"]),
        ])
        .map(normalize_class),
        missing_discriminator: string_path(item, &["missing_discriminator"]),
        related_test: string_path(item, &["suggested_test", "near_test"]),
        suggested_test: string_path(item, &["suggested_test", "assertion_shape"]),
        verify_command: seam_id.as_ref().map(|_| {
            format!(
                "ripr agent verify --root {} --before target/ripr/workflow/before.repo-exposure.json --after target/ripr/workflow/after.repo-exposure.json --json",
                input.root
            )
        }),
        agent_command: seam_id.as_deref().map(|seam_id| {
            format!(
                "ripr agent start --root {} --seam-id {} --out target/ripr/workflow",
                input.root, seam_id
            )
        }),
        receipt: PanelReceipt {
            artifact: None,
            status: "missing".to_string(),
        },
    })
}

fn top_issue_from_gate_decision(
    input: &PrReviewFrontPanelInput,
    parsed: &ParsedPanelSources,
    decision: &str,
) -> Option<PanelTopIssue> {
    let gate = parsed.gate_decision.as_ref()?;
    let item = gate
        .get("decisions")
        .and_then(Value::as_array)?
        .iter()
        .find(|item| string_path(item, &["decision"]).as_deref() == Some(decision))?;
    let seam_id = string_path(item, &["seam_id"]);
    Some(PanelTopIssue {
        source: "gate_decision".to_string(),
        source_artifact: input.gate_decision_path.clone()?,
        seam_id: seam_id.clone(),
        canonical_gap_id: string_path(item, &["canonical_gap_id"]),
        path: string_from_sources(&[
            (Some(item), &["placement", "path"]),
            (Some(item), &["path"]),
        ]),
        line: u64_from_sources(&[
            (Some(item), &["placement", "line"]),
            (Some(item), &["line"]),
        ]),
        classification: Some("weakly_exposed".to_string()),
        missing_discriminator: string_path(item, &["evidence", "missing_discriminator"]),
        related_test: string_path(item, &["evidence", "recommended_test"]),
        suggested_test: string_path(item, &["evidence", "assertion_shape"]),
        verify_command: None,
        agent_command: seam_id.as_deref().and_then(|seam_id| {
            if decision == "acknowledged" {
                Some(format!(
                    "ripr agent start --root {} --seam-id {} --out target/ripr/workflow",
                    input.root, seam_id
                ))
            } else {
                None
            }
        }),
        receipt: PanelReceipt {
            artifact: None,
            status: if decision == "suppressed" {
                "not_available".to_string()
            } else {
                "missing".to_string()
            },
        },
    })
}

fn top_issue_from_baseline_delta(
    input: &PrReviewFrontPanelInput,
    parsed: &ParsedPanelSources,
    bucket: &str,
) -> Option<PanelTopIssue> {
    let delta = parsed.baseline_delta.as_ref()?;
    let item = first_item_with_bucket(delta, bucket)?;
    Some(PanelTopIssue {
        source: "baseline_delta".to_string(),
        source_artifact: input.baseline_delta_path.clone()?,
        seam_id: string_path(item, &["identity", "seam_id"]),
        canonical_gap_id: string_path(item, &["identity", "canonical_gap_id"]),
        path: string_path(item, &["path"]),
        line: u64_path(item, &["line"]),
        classification: string_path(item, &["static_class"]).map(normalize_class),
        missing_discriminator: string_path(item, &["missing_discriminator"]),
        related_test: string_path(item, &["suggested_test", "recommended_test"]),
        suggested_test: string_path(item, &["suggested_test", "assertion_shape"]),
        verify_command: string_path(item, &["repair", "verify_command"]),
        agent_command: None,
        receipt: PanelReceipt {
            artifact: None,
            status: "not_available".to_string(),
        },
    })
}

fn top_issue_from_assistant_health(
    input: &PrReviewFrontPanelInput,
    parsed: &ParsedPanelSources,
) -> Option<PanelTopIssue> {
    let health = parsed.assistant_health.as_ref()?;
    let proof = health
        .get("proofs")
        .and_then(Value::as_array)
        .and_then(|proofs| proofs.first())?;
    let seam = proof.get("seam")?;
    let recommendation = proof.get("recommendation");
    let handoff = proof.get("handoff");
    let receipt = proof.get("receipt");
    Some(PanelTopIssue {
        source: "assistant_health".to_string(),
        source_artifact: input.assistant_health_path.clone()?,
        seam_id: string_path(seam, &["seam_id"]),
        canonical_gap_id: string_path(seam, &["canonical_gap_id"]),
        path: string_path(seam, &["path"]),
        line: u64_path(seam, &["line"]),
        classification: string_path(seam, &["grip_class"]).map(normalize_class),
        missing_discriminator: string_path(seam, &["missing_discriminator"]),
        related_test: recommendation.and_then(|value| string_path(value, &["related_test"])),
        suggested_test: recommendation.and_then(|value| string_path(value, &["suggested_test"])),
        verify_command: recommendation.and_then(|value| string_path(value, &["verify_command"])),
        agent_command: handoff.and_then(|value| string_path(value, &["agent_command"])),
        receipt: PanelReceipt {
            artifact: receipt.and_then(|value| string_path(value, &["artifact"])),
            status: receipt
                .and_then(|value| string_path(value, &["status"]))
                .unwrap_or_else(|| "missing".to_string()),
        },
    })
}

fn first_action_status(first_action: Option<&Value>) -> Option<&str> {
    first_action
        .and_then(|value| value.get("status"))
        .and_then(Value::as_str)
}

fn first_item_with_bucket<'a>(report: &'a Value, bucket: &str) -> Option<&'a Value> {
    report
        .get("items")
        .and_then(Value::as_array)?
        .iter()
        .find(|item| string_path(item, &["bucket"]).as_deref() == Some(bucket))
}

fn has_suppressed(parsed: &ParsedPanelSources) -> bool {
    parsed
        .gate_decision
        .as_ref()
        .and_then(|gate| gate.get("decisions"))
        .and_then(Value::as_array)
        .is_some_and(|items| {
            items
                .iter()
                .any(|item| string_path(item, &["decision"]).as_deref() == Some("suppressed"))
        })
        && parsed
            .gate_decision
            .as_ref()
            .and_then(|gate| string_path(gate, &["status"]))
            .as_deref()
            != Some("acknowledged")
}

fn placement_from_guidance(pr_guidance: Option<&Value>) -> String {
    let Some(guidance) = pr_guidance else {
        return "changed_line".to_string();
    };
    if guidance
        .get("comments")
        .and_then(Value::as_array)
        .is_some_and(|items| !items.is_empty())
    {
        return "changed_line".to_string();
    }
    if guidance
        .get("summary_only")
        .and_then(Value::as_array)
        .is_some_and(|items| !items.is_empty())
    {
        return "summary_only".to_string();
    }
    "not_available".to_string()
}

fn suggested_test_from_action_or_proof(action: &Value, proof: Option<&Value>) -> Option<String> {
    string_from_sources(&[
        (proof, &["recommendation", "suggested_test"]),
        (Some(action), &["target", "suggested_assertion"]),
    ])
    .map(|value| {
        if value.starts_with("Assert the exact ")
            && let Some(rest) = value.strip_prefix("Assert the exact ")
            && let Some((target, condition)) = rest.trim_end_matches('.').split_once(" at ")
        {
            return format!("Add a focused test where {condition} and assert the exact {target}.");
        }
        value
    })
}

fn receipt_from_input(
    receipt_path: Option<&str>,
    receipt_json: Option<&Value>,
    missing_status: &str,
) -> PanelReceipt {
    PanelReceipt {
        artifact: receipt_path.map(ToOwned::to_owned).or_else(|| {
            receipt_json.and_then(|receipt| {
                string_from_sources(&[
                    (Some(receipt), &["provenance", "artifact"]),
                    (Some(receipt), &["receipt"]),
                ])
            })
        }),
        status: if receipt_path.is_some() || receipt_json.is_some() {
            "present".to_string()
        } else {
            missing_status.to_string()
        },
    }
}

fn normalize_class(value: String) -> String {
    match value.as_str() {
        "weakly_gripped" => "weakly_exposed".to_string(),
        "strongly_gripped" => "exposed".to_string(),
        _ => value,
    }
}

fn string_from_sources(sources: &[(Option<&Value>, &[&str])]) -> Option<String> {
    sources
        .iter()
        .find_map(|(value, path)| value.and_then(|value| string_path(value, path)))
}

fn u64_from_sources(sources: &[(Option<&Value>, &[&str])]) -> Option<u64> {
    sources
        .iter()
        .find_map(|(value, path)| value.and_then(|value| u64_path(value, path)))
}

fn usize_from_sources(sources: &[(Option<&Value>, &[&str])]) -> usize {
    sources
        .iter()
        .find_map(|(value, path)| value.and_then(|value| usize_path(value, path)))
        .unwrap_or(0)
}

fn f64_from_sources(sources: &[(Option<&Value>, &[&str])]) -> Option<f64> {
    sources
        .iter()
        .find_map(|(value, path)| value.and_then(|value| f64_path(value, path)))
}

fn i64_from_sources(sources: &[(Option<&Value>, &[&str])]) -> Option<i64> {
    sources
        .iter()
        .find_map(|(value, path)| value.and_then(|value| i64_path(value, path)))
}

fn string_path(value: &Value, path: &[&str]) -> Option<String> {
    path_value(value, path).and_then(value_as_string)
}

fn u64_path(value: &Value, path: &[&str]) -> Option<u64> {
    path_value(value, path).and_then(Value::as_u64)
}

fn usize_path(value: &Value, path: &[&str]) -> Option<usize> {
    path_value(value, path)
        .and_then(Value::as_u64)
        .and_then(|value| usize::try_from(value).ok())
}

fn i64_path(value: &Value, path: &[&str]) -> Option<i64> {
    path_value(value, path).and_then(Value::as_i64)
}

fn f64_path(value: &Value, path: &[&str]) -> Option<f64> {
    path_value(value, path).and_then(Value::as_f64)
}

fn path_value<'a>(value: &'a Value, path: &[&str]) -> Option<&'a Value> {
    let mut current = value;
    for key in path {
        if let Ok(index) = key.parse::<usize>() {
            current = current.get(index)?;
        } else {
            current = current.get(*key)?;
        }
    }
    Some(current)
}

fn value_as_string(value: &Value) -> Option<String> {
    if let Some(text) = value.as_str() {
        return Some(text.to_string());
    }
    if let Some(number) = value.as_i64() {
        return Some(number.to_string());
    }
    value.as_u64().map(|number| number.to_string())
}

fn json_path_to_md(path: &str) -> String {
    if let Some(prefix) = path.strip_suffix(".json") {
        format!("{prefix}.md")
    } else {
        path.to_string()
    }
}

fn issue_location(issue: &PanelTopIssue) -> Option<String> {
    match (issue.path.as_deref(), issue.line) {
        (Some(path), Some(line)) => Some(format!("{path}:{line}")),
        (Some(path), None) => Some(path.to_string()),
        (None, Some(line)) => Some(format!("unknown:{line}")),
        (None, None) => None,
    }
}

fn compact_suggested_test(value: &str) -> String {
    if let Some(predicate) = extract_boundary_subject(value) {
        return format!("add {predicate} boundary assertion");
    }
    value.to_ascii_lowercase()
}

fn extract_boundary_subject(value: &str) -> Option<String> {
    let lower = value.to_ascii_lowercase();
    for marker in [
        "input that hits the boundary:",
        "boundary input where ",
        "boundary test that exercises ",
    ] {
        if let Some(index) = lower.find(marker) {
            return compact_boundary_subject(&value[index + marker.len()..]);
        }
    }
    None
}

fn compact_boundary_subject(value: &str) -> Option<String> {
    let lower = value.to_ascii_lowercase();
    let mut end = value.len();
    for delimiter in [" and assert", " */", "`", "\n", "."] {
        if let Some(index) = lower.find(delimiter) {
            end = end.min(index);
        }
    }
    let subject = value[..end]
        .trim()
        .trim_matches(|c: char| c == '`' || c == ',' || c == ')' || c == ';')
        .trim();
    if subject.is_empty()
        || ![">=", "<=", "==", "!=", ">", "<"]
            .iter()
            .any(|operator| subject.contains(operator))
    {
        return None;
    }
    Some(subject.to_string())
}

fn coverage_grip_markdown(coverage: &PanelCoverageGrip) -> String {
    match coverage.state.as_str() {
        "flat_coverage_grip_improved" => "flat coverage, improved grip".to_string(),
        "not_available" => "not available".to_string(),
        other => other.replace('_', " "),
    }
}

fn percent_or(value: Option<f64>) -> String {
    match value {
        Some(value) if value >= 0.0 => format!("+{value:.1}%"),
        Some(value) => format!("{value:.1}%"),
        None => "not available".to_string(),
    }
}

fn signed_or(value: Option<i64>) -> String {
    match value {
        Some(value) if value > 0 => format!("+{value}"),
        Some(value) => value.to_string(),
        None => "not available".to_string(),
    }
}

fn gate_authority_markdown(policy: &PanelPolicy) -> String {
    match policy.authority_artifact.as_deref() {
        Some(path) if policy.decision == "blocked" => json_path_to_md(path),
        Some(path) => path.to_string(),
        None => "not configured".to_string(),
    }
}

fn artifact_group_label(group: &str) -> &str {
    match group {
        "start_here" => "Start here",
        "repair" => "Repair",
        "evidence" => "Evidence",
        "policy" => "Policy",
        "calibration" => "Calibration",
        "generated_ci" => "Generated CI",
        _ => "Artifact",
    }
}

fn push_count(out: &mut String, label: &str, count: usize) {
    out.push_str(&format!("- {label}: {count}\n"));
}

fn str_or<'a>(value: Option<&'a str>, fallback: &'a str) -> &'a str {
    match value {
        Some(value) => value,
        None => fallback,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::output::test_support::{read_file, repo_root};
    use std::path::Path;

    #[test]
    fn pr_review_front_panel_matches_fixture_corpus() -> Result<(), String> {
        let repo_root = repo_root()?;
        let corpus_path =
            repo_root.join("fixtures/boundary_gap/expected/pr-review-front-panel/corpus.json");
        let corpus: Value = serde_json::from_str(&read_file(&corpus_path)?)
            .map_err(|err| format!("parse corpus failed: {err}"))?;
        let cases = corpus
            .get("cases")
            .and_then(Value::as_array)
            .ok_or_else(|| "corpus cases missing".to_string())?;

        for case in cases {
            let case_id =
                string_path(case, &["id"]).ok_or_else(|| "case id missing".to_string())?;
            let inputs = case
                .get("inputs")
                .ok_or_else(|| format!("{case_id} inputs missing"))?;
            let expected_json_path = repo_root.join(
                string_path(case, &["expected_report"])
                    .ok_or_else(|| format!("{case_id} expected_report missing"))?,
            );
            let expected_md_path = repo_root.join(
                string_path(case, &["expected_markdown"])
                    .ok_or_else(|| format!("{case_id} expected_markdown missing"))?,
            );
            let input = fixture_input(&repo_root, inputs, &expected_md_path)?;
            let report = build_pr_review_front_panel_report(input);

            assert_eq!(
                render_pr_review_front_panel_json(&report)?,
                read_file(&expected_json_path)?.trim_end(),
                "{case_id} JSON fixture drifted"
            );
            assert_eq!(
                render_pr_review_front_panel_markdown(&report),
                read_file(&expected_md_path)?,
                "{case_id} Markdown fixture drifted"
            );
        }
        Ok(())
    }

    #[test]
    fn pr_review_front_panel_reports_malformed_optional_input() -> Result<(), String> {
        let input = PrReviewFrontPanelInput {
            root: ".".to_string(),
            generated_at: "2026-05-09T12:00:00Z".to_string(),
            out_md_path: "target/ripr/reports/pr-review-front-panel.md".to_string(),
            pr_guidance_path: Some("comments.json".to_string()),
            first_action_path: None,
            assistant_proof_path: None,
            assistant_health_path: None,
            ledger_path: None,
            baseline_delta_path: None,
            zero_status_path: None,
            gate_decision_path: None,
            recommendation_calibration_path: None,
            mutation_calibration_path: None,
            coverage_frontier_path: None,
            receipt_path: None,
            pr_guidance_json: Some(Ok("{".to_string())),
            first_action_json: None,
            assistant_proof_json: None,
            assistant_health_json: None,
            ledger_json: None,
            baseline_delta_json: None,
            zero_status_json: None,
            gate_decision_json: None,
            recommendation_calibration_json: None,
            mutation_calibration_json: None,
            coverage_frontier_json: None,
            receipt_json: None,
        };
        let report = build_pr_review_front_panel_report(input);
        let rendered = render_pr_review_front_panel_json(&report)?;
        assert!(rendered.contains("\"kind\": \"malformed_input\""));
        assert!(rendered.contains("Optional PR guidance input is malformed"));
        Ok(())
    }

    #[test]
    fn compact_suggested_test_extracts_boundary_subjects_without_fixture_specific_names() {
        assert_eq!(
            compact_suggested_test(
                "Add a focused boundary test that exercises total <= max_total and assert the exact output."
            ),
            "add total <= max_total boundary assertion"
        );
        assert_eq!(
            compact_suggested_test(
                "assert_eq!(foo(/* boundary input where left != right */), expected)"
            ),
            "add left != right boundary assertion"
        );
        assert_eq!(
            compact_suggested_test("Review RIPR evidence."),
            "review ripr evidence."
        );
    }

    fn fixture_input(
        repo_root: &Path,
        inputs: &Value,
        expected_md_path: &Path,
    ) -> Result<PrReviewFrontPanelInput, String> {
        let pr_guidance = path_from_inputs(inputs, "pr_guidance");
        let first_action = path_from_inputs(inputs, "first_action");
        let assistant_proof = path_from_inputs(inputs, "assistant_proof");
        let assistant_health = path_from_inputs(inputs, "assistant_health");
        let ledger = path_from_inputs(inputs, "ledger");
        let baseline_delta = path_from_inputs(inputs, "baseline_delta");
        let zero_status = path_from_inputs(inputs, "zero_status");
        let gate_decision = path_from_inputs(inputs, "gate_decision");
        let recommendation_calibration = path_from_inputs(inputs, "recommendation_calibration");
        let mutation_calibration = path_from_inputs(inputs, "mutation_calibration");
        let coverage_frontier = path_from_inputs(inputs, "coverage_frontier");
        let receipt = path_from_inputs(inputs, "receipt");

        Ok(PrReviewFrontPanelInput {
            root: string_path(inputs, &["root"]).unwrap_or_else(|| {
                if first_action.is_some() || assistant_health.is_some() {
                    "fixtures/boundary_gap/input".to_string()
                } else {
                    ".".to_string()
                }
            }),
            generated_at: "2026-05-09T12:00:00Z".to_string(),
            out_md_path: fixture_path(repo_root, expected_md_path),
            pr_guidance_json: read_optional_fixture(repo_root, pr_guidance.as_deref())?,
            first_action_json: read_optional_fixture(repo_root, first_action.as_deref())?,
            assistant_proof_json: read_optional_fixture(repo_root, assistant_proof.as_deref())?,
            assistant_health_json: read_optional_fixture(repo_root, assistant_health.as_deref())?,
            ledger_json: read_optional_fixture(repo_root, ledger.as_deref())?,
            baseline_delta_json: read_optional_fixture(repo_root, baseline_delta.as_deref())?,
            zero_status_json: read_optional_fixture(repo_root, zero_status.as_deref())?,
            gate_decision_json: read_optional_fixture(repo_root, gate_decision.as_deref())?,
            recommendation_calibration_json: read_optional_fixture(
                repo_root,
                recommendation_calibration.as_deref(),
            )?,
            mutation_calibration_json: read_optional_fixture(
                repo_root,
                mutation_calibration.as_deref(),
            )?,
            coverage_frontier_json: read_optional_fixture(repo_root, coverage_frontier.as_deref())?,
            receipt_json: read_optional_fixture(repo_root, receipt.as_deref())?,
            pr_guidance_path: pr_guidance,
            first_action_path: first_action,
            assistant_proof_path: assistant_proof,
            assistant_health_path: assistant_health,
            ledger_path: ledger,
            baseline_delta_path: baseline_delta,
            zero_status_path: zero_status,
            gate_decision_path: gate_decision,
            recommendation_calibration_path: recommendation_calibration,
            mutation_calibration_path: mutation_calibration,
            coverage_frontier_path: coverage_frontier,
            receipt_path: receipt,
        })
    }

    fn path_from_inputs(inputs: &Value, key: &str) -> Option<String> {
        inputs.get(key).and_then(value_as_string)
    }

    fn read_optional_fixture(
        repo_root: &Path,
        path: Option<&str>,
    ) -> Result<Option<Result<String, String>>, String> {
        let Some(path) = path else {
            return Ok(None);
        };
        let absolute = repo_root.join(path);
        if absolute.exists() {
            return Ok(Some(Ok(read_file(&absolute)?)));
        }
        Ok(Some(Err(format!(
            "{} does not exist",
            display_path(&absolute)
        ))))
    }

    fn fixture_path(repo_root: &Path, path: &Path) -> String {
        match path.strip_prefix(repo_root) {
            Ok(relative) => display_path(relative),
            Err(_) => display_path(path),
        }
    }
}
