//! AI enrichment abstraction with a deterministic fallback implementation.

use crate::research::heuristics::classify_note;
use crate::research::types::{ModelInfo, NoteType, ResearchNote, SourceKind, ValuationRef};

#[derive(Debug, Clone, PartialEq)]
pub(crate) struct AiEnrichmentResult {
    pub note_type: Option<NoteType>,
    pub annotation: Option<String>,
    pub tags: Vec<String>,
    pub risks: Vec<String>,
    pub catalysts: Vec<String>,
    pub valuation_refs: Vec<ValuationRef>,
    pub missing_evidence: bool,
}

pub(crate) trait ResearchAiGateway: Send + Sync {
    fn enrich_note(&self, note: &ResearchNote, model_info: Option<ModelInfo>)
        -> AiEnrichmentResult;
}

#[derive(Debug, Clone, Default)]
pub(crate) struct DeterministicResearchAiGateway;

impl ResearchAiGateway for DeterministicResearchAiGateway {
    fn enrich_note(
        &self,
        note: &ResearchNote,
        _model_info: Option<ModelInfo>,
    ) -> AiEnrichmentResult {
        let heuristic = classify_note(
            &note.cleaned_text,
            note.provenance.source_kind,
            Some(note.note_type),
        );
        let annotation = Some(build_annotation(note));

        AiEnrichmentResult {
            note_type: Some(heuristic.note_type),
            annotation,
            tags: heuristic.tags,
            risks: heuristic.risks,
            catalysts: heuristic.catalysts,
            valuation_refs: if note.valuation_refs.is_empty() {
                heuristic.valuation_refs
            } else {
                note.valuation_refs.clone()
            },
            missing_evidence: note.source_id.is_none()
                && !matches!(
                    note.note_type,
                    NoteType::Question | NoteType::FollowUpTask | NoteType::SourceReference
                ),
        }
    }
}

fn build_annotation(note: &ResearchNote) -> String {
    let kind = match note.note_type {
        NoteType::ManagementSignal => "Management is signaling a directional read that should be checked against operating evidence.",
        NoteType::ValuationPoint => "This note matters if the valuation frame can be tied to a concrete operating driver.",
        NoteType::Risk => "This note points to downside that should be sized and sourced before it informs conviction.",
        NoteType::Catalyst => "This note suggests a possible stock-moving trigger and should be paired with timing evidence.",
        NoteType::Fact => "This datapoint is most useful when linked directly into a claim, risk, or valuation bridge.",
        NoteType::Quote => "Treat the quote as evidence, then separate the analyst interpretation into linked notes.",
        NoteType::Claim | NoteType::Thesis | NoteType::SubThesis => "This statement is an inference until supporting evidence and explicit counterpoints are attached.",
        NoteType::ChannelCheck => "This datapoint is potentially informative but should be kept caveated unless corroborated.",
        _ => "This note may be more valuable once it is linked into a driver, risk, catalyst, or source trail.",
    };

    if note.source_id.is_none()
        && !matches!(note.note_type, NoteType::Question | NoteType::FollowUpTask)
    {
        format!("{kind} Evidence is still missing or indirect.")
    } else {
        kind.to_string()
    }
}

pub(crate) fn build_model_info(model: &str, task_profile: &str) -> Option<ModelInfo> {
    if model.trim().is_empty() {
        return None;
    }

    Some(ModelInfo {
        task_profile: task_profile.to_string(),
        model: model.to_string(),
        provider: Some("remote".to_string()),
    })
}

#[allow(dead_code)]
fn _kind_from_source(note: &ResearchNote) -> SourceKind {
    note.provenance.source_kind
}
