use serde::Serialize;
use talon_core::{InspectCheck, InspectFinding, InspectResponse};

#[derive(Debug, Serialize)]
pub(super) struct AgentInspect<'a> {
    #[serde(skip_serializing_if = "Option::is_none")]
    vault: Option<&'a str>,
    total: usize,
    checks: AgentInspectChecks<'a>,
}

#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
struct AgentInspectChecks<'a> {
    #[serde(skip_serializing_if = "Vec::is_empty")]
    orphans: Vec<AgentInspectFinding<'a>>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    broken_links: Vec<AgentInspectFinding<'a>>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    dangling_refs: Vec<AgentInspectFinding<'a>>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    unreferenced: Vec<AgentInspectFinding<'a>>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    graph: Vec<AgentInspectFinding<'a>>,
}

#[derive(Debug, Serialize)]
struct AgentInspectFinding<'a> {
    path: &'a str,
    message: &'a str,
    #[serde(skip_serializing_if = "Option::is_none")]
    line: Option<u32>,
}

impl<'a> From<&'a InspectResponse> for AgentInspect<'a> {
    fn from(resp: &'a InspectResponse) -> Self {
        let mut checks = AgentInspectChecks::default();
        for finding in &resp.findings {
            checks.push(finding);
        }
        Self {
            vault: resp.vault.as_ref().map(talon_core::ContainerPath::as_str),
            total: resp.findings.len(),
            checks,
        }
    }
}

impl<'a> AgentInspectChecks<'a> {
    fn push(&mut self, finding: &'a InspectFinding) {
        let compact = AgentInspectFinding {
            path: finding.path.as_str(),
            message: &finding.message,
            line: finding.line,
        };
        match finding.check {
            InspectCheck::All => {}
            InspectCheck::Orphans => self.orphans.push(compact),
            InspectCheck::BrokenLinks => self.broken_links.push(compact),
            InspectCheck::DanglingRefs => self.dangling_refs.push(compact),
            InspectCheck::Unreferenced => self.unreferenced.push(compact),
            InspectCheck::Graph => self.graph.push(compact),
        }
    }
}
