//! Core types for the reasoning engine.

use serde::{Deserialize, Serialize};

/// Classification of what kind of code problem this is.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ProblemClass {
    BugFix,
    Refactor,
    Architecture,
    NewFeature,
    Performance,
    TestWriting,
    Explanation,
    Unknown,
}

impl ProblemClass {
    /// Keywords that identify this problem class (for skill triggers).
    pub fn keywords(&self) -> Vec<String> {
        match self {
            ProblemClass::BugFix => {
                vec!["bug", "fix", "broken", "error", "crash", "wrong", "failing"]
            }
            ProblemClass::Refactor => {
                vec!["refactor", "clean", "simplify", "restructure", "rename"]
            }
            ProblemClass::Architecture => {
                vec!["architecture", "design", "pattern", "structure", "approach"]
            }
            ProblemClass::NewFeature => {
                vec!["add", "implement", "create", "feature", "new", "build"]
            }
            ProblemClass::Performance => vec![
                "slow",
                "fast",
                "optimize",
                "performance",
                "memory",
                "latency",
            ],
            ProblemClass::TestWriting => vec!["test", "coverage", "assert", "mock", "spec"],
            ProblemClass::Explanation => vec!["explain", "why", "how", "what", "understand"],
            ProblemClass::Unknown => vec![],
        }
        .into_iter()
        .map(String::from)
        .collect()
    }

    /// Parse from a classification model's output.
    pub fn from_label(s: &str) -> Self {
        let lower = s.to_lowercase();
        if lower.contains("bug") || lower.contains("fix") {
            ProblemClass::BugFix
        } else if lower.contains("refactor") {
            ProblemClass::Refactor
        } else if lower.contains("architect") {
            ProblemClass::Architecture
        } else if lower.contains("feature") || lower.contains("implement") {
            ProblemClass::NewFeature
        } else if lower.contains("perf") || lower.contains("optim") {
            ProblemClass::Performance
        } else if lower.contains("test") {
            ProblemClass::TestWriting
        } else if lower.contains("explain") {
            ProblemClass::Explanation
        } else {
            ProblemClass::Unknown
        }
    }
}

impl std::fmt::Display for ProblemClass {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ProblemClass::BugFix => write!(f, "bug_fix"),
            ProblemClass::Refactor => write!(f, "refactor"),
            ProblemClass::Architecture => write!(f, "architecture"),
            ProblemClass::NewFeature => write!(f, "new_feature"),
            ProblemClass::Performance => write!(f, "performance"),
            ProblemClass::TestWriting => write!(f, "test_writing"),
            ProblemClass::Explanation => write!(f, "explanation"),
            ProblemClass::Unknown => write!(f, "unknown"),
        }
    }
}

/// A discrete reasoning step.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ActionKind {
    /// Determine problem class.
    Classify,
    /// Find relevant code/files in the codebase.
    Locate,
    /// Pull similar past fixes from graph memory.
    RetrievePatterns,
    /// Root cause analysis.
    Diagnose,
    /// Produce a code suggestion.
    GenerateFix,
    /// Static/formal verification of the suggestion.
    VerifyFix,
    /// Human-readable explanation.
    Explain,
}

impl ActionKind {
    /// Skill name in the memgine graph.
    pub fn skill_name(&self) -> String {
        format!("reason:{self}")
    }

    /// Temperature for this action (lower = more deterministic).
    pub fn temperature(&self) -> f64 {
        match self {
            ActionKind::Classify => 0.0,
            ActionKind::Locate => 0.1,
            ActionKind::RetrievePatterns => 0.0,
            ActionKind::Diagnose => 0.4,
            ActionKind::GenerateFix => 0.3,
            ActionKind::VerifyFix => 0.0,
            ActionKind::Explain => 0.5,
        }
    }

    /// Max tokens for this action.
    pub fn max_tokens(&self) -> usize {
        match self {
            ActionKind::Classify => 50,
            ActionKind::Locate => 512,
            ActionKind::RetrievePatterns => 256,
            ActionKind::Diagnose => 1024,
            ActionKind::GenerateFix => 2048,
            ActionKind::VerifyFix => 256,
            ActionKind::Explain => 1024,
        }
    }
}

impl std::fmt::Display for ActionKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            ActionKind::Classify => write!(f, "classify"),
            ActionKind::Locate => write!(f, "locate"),
            ActionKind::RetrievePatterns => write!(f, "retrieve_patterns"),
            ActionKind::Diagnose => write!(f, "diagnose"),
            ActionKind::GenerateFix => write!(f, "generate_fix"),
            ActionKind::VerifyFix => write!(f, "verify_fix"),
            ActionKind::Explain => write!(f, "explain"),
        }
    }
}

/// Configuration for a reasoning action, stored as the skill's `code` field in the graph.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActionConfig {
    pub kind: ActionKind,
    /// Which problem classes this action applies to.
    pub applicable_to: Vec<ProblemClass>,
    /// Prerequisite actions that must complete before this one.
    pub prerequisites: Vec<ActionKind>,
    /// Prompt template with placeholders: {problem}, {context}, {patterns}, {diagnosis}, {code}
    pub prompt_template: String,
    /// Execution priority (lower = earlier). Graph can override via activation scores.
    pub priority: u32,
}

/// The result of executing a single reasoning action.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActionOutcome {
    pub action: ActionKind,
    pub model_used: String,
    pub trace_id: String,
    pub latency_ms: u64,
    pub output: String,
    pub confidence: f64,
    pub success: bool,
}

/// A code suggestion with confidence and verification status.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CodeSuggestion {
    pub file_path: Option<String>,
    pub original: Option<String>,
    pub suggested: String,
    pub confidence: f64,
    pub verification: VerificationStatus,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum VerificationStatus {
    NotVerified,
    Passed,
    Failed,
    PartiallyVerified,
}

/// The complete output of a reasoning session.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReasoningResult {
    pub session_id: String,
    pub problem_class: ProblemClass,
    pub diagnosis: String,
    pub suggestions: Vec<CodeSuggestion>,
    pub explanation: String,
    pub actions_taken: Vec<ActionOutcome>,
    pub overall_confidence: f64,
    pub total_latency_ms: u64,
}
