use serde::{Deserialize, Serialize};

/// Severity of a review finding
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum Severity {
    /// Critical issue that must be fixed
    Critical,
    /// High priority issue
    High,
    /// Medium priority issue
    #[default]
    Medium,
    /// Low priority issue
    Low,
    /// Informational note
    Info,
}

impl std::fmt::Display for Severity {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Critical => write!(f, "critical"),
            Self::High => write!(f, "high"),
            Self::Medium => write!(f, "medium"),
            Self::Low => write!(f, "low"),
            Self::Info => write!(f, "info"),
        }
    }
}

impl Severity {
    /// Returns a numeric rank for comparison (higher = more severe)
    pub fn rank(&self) -> u8 {
        match self {
            Self::Critical => 5,
            Self::High => 4,
            Self::Medium => 3,
            Self::Low => 2,
            Self::Info => 1,
        }
    }
}

/// Category of code review finding
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum ReviewCategory {
    /// Potential bugs
    #[default]
    Bugs,
    /// Best practices violations
    BestPractices,
    /// Security issues
    Security,
    /// Performance concerns
    Performance,
    /// Code that could be simplified
    Simplification,
}

impl std::fmt::Display for ReviewCategory {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Bugs => write!(f, "bugs"),
            Self::BestPractices => write!(f, "best_practices"),
            Self::Security => write!(f, "security"),
            Self::Performance => write!(f, "performance"),
            Self::Simplification => write!(f, "simplification"),
        }
    }
}

/// Status of a review session
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum ReviewStatus {
    /// Review not yet started
    #[default]
    Pending,
    /// Review in progress
    InProgress,
    /// Review completed
    Complete,
    /// Review approved (all issues resolved or accepted)
    Approved,
}

impl std::fmt::Display for ReviewStatus {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Pending => write!(f, "pending"),
            Self::InProgress => write!(f, "in_progress"),
            Self::Complete => write!(f, "complete"),
            Self::Approved => write!(f, "approved"),
        }
    }
}

/// A single finding from code review
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReviewFinding {
    /// Unique identifier
    pub id: String,
    /// Category of the finding
    pub category: ReviewCategory,
    /// File where the issue was found
    pub file: String,
    /// Line number (if applicable)
    #[serde(skip_serializing_if = "Option::is_none")]
    pub line: Option<u32>,
    /// Severity of the issue
    pub severity: Severity,
    /// Description of the issue
    pub description: String,
    /// Suggested fix
    #[serde(skip_serializing_if = "Option::is_none")]
    pub suggestion: Option<String>,
    /// Whether the issue has been resolved
    #[serde(default)]
    pub resolved: bool,
}

impl ReviewFinding {
    pub fn new(
        id: impl Into<String>,
        category: ReviewCategory,
        file: impl Into<String>,
        severity: Severity,
        description: impl Into<String>,
    ) -> Self {
        Self {
            id: id.into(),
            category,
            file: file.into(),
            line: None,
            severity,
            description: description.into(),
            suggestion: None,
            resolved: false,
        }
    }

    pub fn with_line(mut self, line: u32) -> Self {
        self.line = Some(line);
        self
    }

    pub fn with_suggestion(mut self, suggestion: impl Into<String>) -> Self {
        self.suggestion = Some(suggestion.into());
        self
    }
}

/// A code review session
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReviewSession {
    /// Unique identifier
    pub id: String,
    /// Name of the task being reviewed
    pub task_name: String,
    /// Iteration number (1-based)
    pub iteration: u32,
    /// Current status
    pub status: ReviewStatus,
    /// When the review was created
    pub created_at: String,
    /// When the review was completed
    #[serde(skip_serializing_if = "Option::is_none")]
    pub completed_at: Option<String>,
    /// Files that were reviewed
    #[serde(default)]
    pub files_reviewed: Vec<String>,
    /// Findings from the review
    #[serde(default)]
    pub findings: Vec<ReviewFinding>,
}

impl ReviewSession {
    pub fn new(id: impl Into<String>, task_name: impl Into<String>, iteration: u32) -> Self {
        Self {
            id: id.into(),
            task_name: task_name.into(),
            iteration,
            status: ReviewStatus::Pending,
            created_at: chrono::Utc::now().to_rfc3339(),
            completed_at: None,
            files_reviewed: Vec::new(),
            findings: Vec::new(),
        }
    }

    pub fn unresolved_findings(&self) -> Vec<&ReviewFinding> {
        self.findings.iter().filter(|f| !f.resolved).collect()
    }

    pub fn critical_findings(&self) -> Vec<&ReviewFinding> {
        self.findings
            .iter()
            .filter(|f| f.severity == Severity::Critical && !f.resolved)
            .collect()
    }

    pub fn high_findings(&self) -> Vec<&ReviewFinding> {
        self.findings
            .iter()
            .filter(|f| f.severity == Severity::High && !f.resolved)
            .collect()
    }

    pub fn complete(&mut self) {
        self.status = ReviewStatus::Complete;
        self.completed_at = Some(chrono::Utc::now().to_rfc3339());
    }

    pub fn approve(&mut self) {
        self.status = ReviewStatus::Approved;
        self.completed_at = Some(chrono::Utc::now().to_rfc3339());
    }
}

/// Summary of a review session
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ReviewSummary {
    pub id: String,
    pub iteration: u32,
    pub status: ReviewStatus,
    pub total_findings: usize,
    pub unresolved_findings: usize,
    pub critical_findings: usize,
    pub high_findings: usize,
}

impl From<&ReviewSession> for ReviewSummary {
    fn from(session: &ReviewSession) -> Self {
        Self {
            id: session.id.clone(),
            iteration: session.iteration,
            status: session.status.clone(),
            total_findings: session.findings.len(),
            unresolved_findings: session.unresolved_findings().len(),
            critical_findings: session.critical_findings().len(),
            high_findings: session.high_findings().len(),
        }
    }
}

/// Status of the iteration limit check
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct IterationStatus {
    pub current_iteration: u32,
    pub max_iterations: u32,
    pub should_continue: bool,
    pub needs_human_intervention: bool,
    pub message: String,
}

impl IterationStatus {
    pub fn new(current: u32, max: u32) -> Self {
        let needs_human = current >= max;
        Self {
            current_iteration: current,
            max_iterations: max,
            should_continue: !needs_human,
            needs_human_intervention: needs_human,
            message: if needs_human {
                format!(
                    "Maximum review iterations ({}) reached. Would you like to continue with more iterations?",
                    max
                )
            } else {
                format!(
                    "Iteration {}/{} - within limit, can continue.",
                    current, max
                )
            },
        }
    }
}
