use std::collections::{BTreeMap, BTreeSet};

use eidos_kernel::schema::Graph;

use super::model::*;

pub(crate) fn score_nodes(
    graph: &Graph,
    incoming: &BTreeMap<String, usize>,
    outgoing: &BTreeMap<String, usize>,
    findings: &[QualityFinding],
) -> Vec<NodeQualityScore> {
    let unresolved: BTreeSet<String> = findings
        .iter()
        .filter(|f| {
            matches!(
                f.kind,
                QualityFindingKind::UnresolvedWikilink
                    | QualityFindingKind::BrokenInternalMarkdownLink
                    | QualityFindingKind::BrokenIndexLink
                    | QualityFindingKind::UnresolvedFrontmatterTarget
            )
        })
        .filter_map(|f| f.node_id.clone())
        .collect();

    graph
        .nodes
        .iter()
        .map(|node| {
            let has_incoming = incoming.get(&node.id).copied().unwrap_or_default() > 0;
            let has_outgoing = outgoing.get(&node.id).copied().unwrap_or_default() > 0;
            let criteria = [
                ("has_title", !node.title.trim().is_empty()),
                ("has_summary", !node.summary.trim().is_empty()),
                (
                    "has_searchable_body_or_query_examples",
                    !node.query_examples.is_empty(),
                ),
                (
                    "has_aliases_tags_or_query_examples",
                    !node.aliases.is_empty() || !node.query_examples.is_empty(),
                ),
                ("has_outgoing_trusted_relation_or_link", has_outgoing),
                ("has_incoming_trusted_relation_or_link", has_incoming),
                (
                    "has_any_trusted_relation_or_link",
                    has_incoming || has_outgoing,
                ),
                (
                    "has_no_unresolved_outgoing_targets",
                    !unresolved.contains(&node.id),
                ),
            ];
            let mut passed = Vec::new();
            let mut missing = Vec::new();
            for (criterion, ok) in criteria {
                if ok {
                    passed.push(criterion.to_string());
                } else {
                    missing.push(criterion.to_string());
                }
            }
            NodeQualityScore {
                node_id: node.id.clone(),
                score: passed.len() as u8,
                max_score: criteria.len() as u8,
                passed,
                missing,
            }
        })
        .collect()
}
