//! Lifecycle command handlers for knowledge deprecation and migration tracking.

use std::process::ExitCode;

use chrono::{NaiveDate, Utc};
use uuid::Uuid;

use aphoria::{
    learning_store_dir, AphoriaConfig, DeprecatedUsage, KnowledgeStatus, LifecycleStore,
    LocalPatternStore, MigrationProgress, MigrationStore, PatternStore, StatusTransition,
};

use crate::cli::{LifecycleCommands, MigrationCommands};

/// Handle lifecycle subcommands.
pub async fn handle_lifecycle_command(
    command: LifecycleCommands,
    config: &AphoriaConfig,
) -> ExitCode {
    match command {
        LifecycleCommands::Deprecate {
            pattern_id,
            reason,
            superseded_by,
            sunset_date,
            migration_guide,
        } => {
            handle_deprecate(
                &pattern_id,
                &reason,
                superseded_by.as_deref(),
                sunset_date.as_deref(),
                migration_guide,
                config,
            )
            .await
        }
        LifecycleCommands::Archive { pattern_id, reason } => {
            handle_archive(&pattern_id, &reason, config).await
        }
        LifecycleCommands::Reactivate { pattern_id, reason } => {
            handle_reactivate(&pattern_id, &reason, config).await
        }
        LifecycleCommands::History { pattern_id, format } => {
            handle_history(&pattern_id, &format, config).await
        }
        LifecycleCommands::List { status, overdue, format } => {
            handle_list(status.as_deref(), overdue, &format, config).await
        }
    }
}

/// Handle migrations subcommands.
pub async fn handle_migrations_command(
    command: MigrationCommands,
    config: &AphoriaConfig,
) -> ExitCode {
    match command {
        MigrationCommands::Status { pattern, scope, format } => {
            handle_migration_status(pattern.as_deref(), scope.as_deref(), &format, config).await
        }
        MigrationCommands::Export { output, format, include_resolved } => {
            handle_migration_export(&output, &format, include_resolved, config).await
        }
        MigrationCommands::Blockers { pattern_id, scope } => {
            handle_migration_blockers(&pattern_id, scope.as_deref(), config).await
        }
    }
}

/// Deprecate a pattern.
async fn handle_deprecate(
    pattern_id: &str,
    reason: &str,
    superseded_by: Option<&str>,
    sunset_date: Option<&str>,
    migration_guide: Option<String>,
    _config: &AphoriaConfig,
) -> ExitCode {
    // Parse pattern ID
    let id = match Uuid::parse_str(pattern_id) {
        Ok(id) => id,
        Err(e) => {
            eprintln!("Invalid pattern ID '{}': {}", pattern_id, e);
            return ExitCode::from(1);
        }
    };

    // Parse superseded_by if provided
    let superseded_by_id = if let Some(s) = superseded_by {
        match Uuid::parse_str(s) {
            Ok(id) => Some(id),
            Err(e) => {
                eprintln!("Invalid superseded-by ID '{}': {}", s, e);
                return ExitCode::from(1);
            }
        }
    } else {
        None
    };

    // Parse sunset date if provided
    let sunset_datetime = if let Some(date_str) = sunset_date {
        match NaiveDate::parse_from_str(date_str, "%Y-%m-%d") {
            Ok(date) => {
                let datetime = date.and_hms_opt(23, 59, 59);
                datetime.map(|dt| chrono::TimeZone::from_utc_datetime(&Utc, &dt))
            }
            Err(e) => {
                eprintln!("Invalid sunset date '{}': {}. Use YYYY-MM-DD format.", date_str, e);
                return ExitCode::from(1);
            }
        }
    } else {
        None
    };

    // Load pattern store to verify pattern exists
    let pattern_store = match LocalPatternStore::new(&learning_store_dir()) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open pattern store: {}", e);
            return ExitCode::from(1);
        }
    };

    let pattern = match pattern_store.get_pattern_by_id(&id) {
        Some(p) => p,
        None => {
            eprintln!("Pattern '{}' not found", pattern_id);
            return ExitCode::from(1);
        }
    };

    // Create lifecycle store
    let lifecycle_store = match LifecycleStore::open_default() {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open lifecycle store: {}", e);
            return ExitCode::from(1);
        }
    };

    // Get current status
    let current_status = lifecycle_store.get_current_status(&id).unwrap_or(KnowledgeStatus::Active);

    // Create new deprecated status
    let new_status = KnowledgeStatus::Deprecated {
        reason: reason.to_string(),
        superseded_by: superseded_by_id,
        sunset_date: sunset_datetime,
        migration_guide,
    };

    // Record transition
    let transition = StatusTransition::new(
        id,
        current_status,
        new_status.clone(),
        whoami::username(),
        Some(format!("Deprecated: {}", reason)),
    );

    if let Err(e) = lifecycle_store.record_transition(transition) {
        eprintln!("Failed to record transition: {}", e);
        return ExitCode::from(1);
    }

    // Display result
    println!("Pattern deprecated successfully");
    println!();
    println!("  Pattern ID:    {}", id);
    println!("  Pattern Name:  {}", pattern.claim_template.predicate);
    println!("  Reason:        {}", reason);

    if let Some(s) = superseded_by_id {
        println!("  Superseded By: {}", s);
    }

    if let Some(date) = sunset_datetime {
        println!("  Sunset Date:   {}", date.format("%Y-%m-%d"));
    }

    println!();
    println!("Scans will now FLAG this pattern with migration guidance.");

    ExitCode::SUCCESS
}

/// Archive a pattern.
async fn handle_archive(pattern_id: &str, reason: &str, _config: &AphoriaConfig) -> ExitCode {
    let id = match Uuid::parse_str(pattern_id) {
        Ok(id) => id,
        Err(e) => {
            eprintln!("Invalid pattern ID '{}': {}", pattern_id, e);
            return ExitCode::from(1);
        }
    };

    // Load pattern store to verify pattern exists
    let pattern_store = match LocalPatternStore::new(&learning_store_dir()) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open pattern store: {}", e);
            return ExitCode::from(1);
        }
    };

    if pattern_store.get_pattern_by_id(&id).is_none() {
        eprintln!("Pattern '{}' not found", pattern_id);
        return ExitCode::from(1);
    }

    // Create lifecycle store
    let lifecycle_store = match LifecycleStore::open_default() {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open lifecycle store: {}", e);
            return ExitCode::from(1);
        }
    };

    let current_status = lifecycle_store.get_current_status(&id).unwrap_or(KnowledgeStatus::Active);

    let new_status =
        KnowledgeStatus::Archived { archived_at: Utc::now(), reason: reason.to_string() };

    let transition = StatusTransition::new(
        id,
        current_status,
        new_status,
        whoami::username(),
        Some(format!("Archived: {}", reason)),
    );

    if let Err(e) = lifecycle_store.record_transition(transition) {
        eprintln!("Failed to record transition: {}", e);
        return ExitCode::from(1);
    }

    println!("Pattern archived successfully");
    println!();
    println!("  Pattern ID: {}", id);
    println!("  Reason:     {}", reason);
    println!();
    println!("Pattern will no longer match during scans.");

    ExitCode::SUCCESS
}

/// Reactivate a deprecated pattern.
async fn handle_reactivate(pattern_id: &str, reason: &str, _config: &AphoriaConfig) -> ExitCode {
    let id = match Uuid::parse_str(pattern_id) {
        Ok(id) => id,
        Err(e) => {
            eprintln!("Invalid pattern ID '{}': {}", pattern_id, e);
            return ExitCode::from(1);
        }
    };

    // Load pattern store
    let pattern_store = match LocalPatternStore::new(&learning_store_dir()) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open pattern store: {}", e);
            return ExitCode::from(1);
        }
    };

    if pattern_store.get_pattern_by_id(&id).is_none() {
        eprintln!("Pattern '{}' not found", pattern_id);
        return ExitCode::from(1);
    }

    // Create lifecycle store
    let lifecycle_store = match LifecycleStore::open_default() {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open lifecycle store: {}", e);
            return ExitCode::from(1);
        }
    };

    let current_status = match lifecycle_store.get_current_status(&id) {
        Some(s) => s,
        None => {
            eprintln!("Pattern has no lifecycle history (already active)");
            return ExitCode::from(1);
        }
    };

    if !current_status.is_deprecated() {
        eprintln!("Pattern is not deprecated (status: {})", current_status.status_name());
        return ExitCode::from(1);
    }

    let transition = StatusTransition::new(
        id,
        current_status,
        KnowledgeStatus::Active,
        whoami::username(),
        Some(format!("Reactivated: {}", reason)),
    );

    if let Err(e) = lifecycle_store.record_transition(transition) {
        eprintln!("Failed to record transition: {}", e);
        return ExitCode::from(1);
    }

    println!("Pattern reactivated successfully");
    println!();
    println!("  Pattern ID: {}", id);
    println!("  Reason:     {}", reason);
    println!();
    println!("Pattern is now active and will match without deprecation warnings.");

    ExitCode::SUCCESS
}

/// Show lifecycle history for a pattern.
async fn handle_history(pattern_id: &str, format: &str, _config: &AphoriaConfig) -> ExitCode {
    let id = match Uuid::parse_str(pattern_id) {
        Ok(id) => id,
        Err(e) => {
            eprintln!("Invalid pattern ID '{}': {}", pattern_id, e);
            return ExitCode::from(1);
        }
    };

    let lifecycle_store = match LifecycleStore::open_default() {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open lifecycle store: {}", e);
            return ExitCode::from(1);
        }
    };

    let history = lifecycle_store.get_history(&id);

    if history.is_empty() {
        println!("No lifecycle history for pattern {}", pattern_id);
        println!();
        println!("Pattern is in Active status (default).");
        return ExitCode::SUCCESS;
    }

    match format {
        "json" => {
            let json = serde_json::to_string_pretty(&history).unwrap_or_else(|_| "[]".to_string());
            println!("{}", json);
        }
        _ => {
            println!("Lifecycle History for {}", pattern_id);
            println!("{}", "=".repeat(60));
            println!();

            for transition in &history {
                let arrow = "→";
                println!(
                    "{} {} {} → {}",
                    transition.timestamp.format("%Y-%m-%d %H:%M"),
                    arrow,
                    transition.from_status.status_name(),
                    transition.to_status.status_name()
                );
                println!("  By: {}", transition.initiated_by);
                if let Some(ref comment) = transition.comment {
                    println!("  Comment: {}", comment);
                }
                println!();
            }
        }
    }

    ExitCode::SUCCESS
}

/// List patterns by lifecycle status.
async fn handle_list(
    status_filter: Option<&str>,
    overdue: bool,
    format: &str,
    _config: &AphoriaConfig,
) -> ExitCode {
    let lifecycle_store = match LifecycleStore::open_default() {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open lifecycle store: {}", e);
            return ExitCode::from(1);
        }
    };

    let pattern_store = match LocalPatternStore::new(&learning_store_dir()) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open pattern store: {}", e);
            return ExitCode::from(1);
        }
    };

    // Collect patterns with their status
    let mut results: Vec<(Uuid, String, KnowledgeStatus)> = Vec::new();

    // Get all patterns and their statuses
    for pattern in pattern_store.get_all_patterns() {
        let status =
            lifecycle_store.get_current_status(&pattern.id).unwrap_or(KnowledgeStatus::Active);

        // Apply filters
        if let Some(filter) = status_filter {
            if status.status_name() != filter {
                continue;
            }
        }

        if overdue && !status.is_past_sunset() {
            continue;
        }

        results.push((pattern.id, pattern.claim_template.predicate.clone(), status));
    }

    if results.is_empty() {
        println!("No patterns found matching criteria.");
        return ExitCode::SUCCESS;
    }

    match format {
        "json" => {
            let json_data: Vec<serde_json::Value> = results
                .iter()
                .map(|(id, name, status)| {
                    serde_json::json!({
                        "id": id.to_string(),
                        "name": name,
                        "status": status.status_name(),
                        "days_until_sunset": status.days_until_sunset(),
                    })
                })
                .collect();
            let json =
                serde_json::to_string_pretty(&json_data).unwrap_or_else(|_| "[]".to_string());
            println!("{}", json);
        }
        _ => {
            println!("Patterns by Lifecycle Status");
            println!("{}", "=".repeat(60));
            println!();

            for (id, name, status) in &results {
                let sunset_info = status
                    .days_until_sunset()
                    .map(|d| {
                        if d < 0 {
                            format!(" (OVERDUE by {} days)", -d)
                        } else {
                            format!(" ({} days until sunset)", d)
                        }
                    })
                    .unwrap_or_default();

                println!("{:<40} {:<12} {}", name, status.status_name(), sunset_info);
                println!("  {}", id);
            }

            println!();
            println!("Total: {} patterns", results.len());
        }
    }

    ExitCode::SUCCESS
}

/// Show migration status for deprecated patterns.
async fn handle_migration_status(
    pattern_filter: Option<&str>,
    _scope_filter: Option<&str>,
    format: &str,
    _config: &AphoriaConfig,
) -> ExitCode {
    let migration_store = match MigrationStore::open_default() {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open migration store: {}", e);
            return ExitCode::from(1);
        }
    };

    let lifecycle_store = match LifecycleStore::open_default() {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open lifecycle store: {}", e);
            return ExitCode::from(1);
        }
    };

    let pattern_store = match LocalPatternStore::new(&learning_store_dir()) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open pattern store: {}", e);
            return ExitCode::from(1);
        }
    };

    // Get deprecated patterns
    let deprecated = lifecycle_store.get_deprecated_patterns();

    if deprecated.is_empty() {
        println!("No deprecated patterns found.");
        return ExitCode::SUCCESS;
    }

    let mut progress_list: Vec<MigrationProgress> = Vec::new();

    for (pattern_id, _status) in &deprecated {
        // Apply pattern filter if specified
        if let Some(filter) = pattern_filter {
            if let Ok(filter_id) = Uuid::parse_str(filter) {
                if pattern_id != &filter_id {
                    continue;
                }
            }
        }

        // Get pattern name
        let pattern_name = pattern_store
            .get_pattern_by_id(pattern_id)
            .map(|p| p.claim_template.predicate.clone())
            .unwrap_or_else(|| "Unknown".to_string());

        let progress = migration_store.get_progress(pattern_id, &pattern_name);
        progress_list.push(progress);
    }

    if progress_list.is_empty() {
        println!("No migration data found.");
        return ExitCode::SUCCESS;
    }

    match format {
        "json" => {
            let json =
                serde_json::to_string_pretty(&progress_list).unwrap_or_else(|_| "[]".to_string());
            println!("{}", json);
        }
        _ => {
            println!("Migration Status");
            println!("{}", "=".repeat(70));
            println!();
            println!("{:<30} {:>8} {:>8} {:>10}", "Pattern", "Total", "Resolved", "Progress");
            println!("{}", "-".repeat(70));

            for progress in &progress_list {
                println!(
                    "{:<30} {:>8} {:>8} {:>9.1}%",
                    truncate(&progress.pattern_name, 30),
                    progress.total_usages,
                    progress.resolved_usages,
                    progress.completion_percent()
                );
            }

            println!();
            let total_usages: usize = progress_list.iter().map(|p| p.total_usages).sum();
            let total_resolved: usize = progress_list.iter().map(|p| p.resolved_usages).sum();
            let overall_percent = if total_usages > 0 {
                (total_resolved as f32 / total_usages as f32) * 100.0
            } else {
                100.0
            };

            println!(
                "Overall: {} of {} usages resolved ({:.1}%)",
                total_resolved, total_usages, overall_percent
            );
        }
    }

    ExitCode::SUCCESS
}

/// Export migration data.
async fn handle_migration_export(
    output: &std::path::Path,
    format: &str,
    include_resolved: bool,
    _config: &AphoriaConfig,
) -> ExitCode {
    let migration_store = match MigrationStore::open_default() {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open migration store: {}", e);
            return ExitCode::from(1);
        }
    };

    let content = match format {
        "csv" => migration_store.export_csv(include_resolved),
        "json" => {
            // For JSON, we need to manually build the data
            let lifecycle_store = match LifecycleStore::open_default() {
                Ok(s) => s,
                Err(e) => {
                    eprintln!("Failed to open lifecycle store: {}", e);
                    return ExitCode::from(1);
                }
            };

            let deprecated = lifecycle_store.get_deprecated_patterns();
            let mut all_usages: Vec<DeprecatedUsage> = Vec::new();

            for (pattern_id, _) in deprecated {
                let usages = if include_resolved {
                    migration_store.get_usages(&pattern_id)
                } else {
                    migration_store.get_pending_usages(&pattern_id)
                };
                all_usages.extend(usages);
            }

            serde_json::to_string_pretty(&all_usages).unwrap_or_else(|_| "[]".to_string())
        }
        _ => {
            eprintln!("Unknown format '{}'. Use 'csv' or 'json'.", format);
            return ExitCode::from(1);
        }
    };

    if let Err(e) = std::fs::write(output, content) {
        eprintln!("Failed to write to {}: {}", output.display(), e);
        return ExitCode::from(1);
    }

    println!("Exported migration data to {}", output.display());

    ExitCode::SUCCESS
}

/// Show migration blockers for a pattern.
async fn handle_migration_blockers(
    pattern_id: &str,
    _scope_filter: Option<&str>,
    _config: &AphoriaConfig,
) -> ExitCode {
    let id = match Uuid::parse_str(pattern_id) {
        Ok(id) => id,
        Err(e) => {
            eprintln!("Invalid pattern ID '{}': {}", pattern_id, e);
            return ExitCode::from(1);
        }
    };

    let migration_store = match MigrationStore::open_default() {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open migration store: {}", e);
            return ExitCode::from(1);
        }
    };

    let pending = migration_store.get_pending_usages(&id);

    if pending.is_empty() {
        println!("No pending usages found for pattern {}", pattern_id);
        println!();
        println!("Migration is complete.");
        return ExitCode::SUCCESS;
    }

    println!("Migration Blockers for {}", pattern_id);
    println!("{}", "=".repeat(70));
    println!();

    for usage in &pending {
        println!("{}:{}", usage.file_path, usage.line);
        println!("  Project: {}", &usage.project_hash[..8.min(usage.project_hash.len())]);
        println!("  First seen: {}", usage.first_detected.format("%Y-%m-%d"));
        println!("  Last seen:  {}", usage.last_detected.format("%Y-%m-%d"));
        println!();
    }

    println!("Total blockers: {}", pending.len());

    ExitCode::SUCCESS
}

/// Truncate a string to a maximum length.
fn truncate(s: &str, max: usize) -> String {
    if s.len() <= max {
        s.to_string()
    } else {
        format!("{}...", &s[..max - 3])
    }
}
