//! Governance command handlers for approval workflows and audit trails.

use std::path::Path;
use std::process::ExitCode;

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

use aphoria::{
    learning_store_dir, AphoriaConfig, ApprovalRequest, ApprovalStatus, AuditTrail, ExportFormat,
    GovernanceStateMachine, GovernanceStore, LocalPatternStore, PatternStore,
};

use crate::cli::{AuditCommands, GovernanceCommands};

/// Handle governance subcommands.
pub async fn handle_governance_command(
    command: GovernanceCommands,
    config: &AphoriaConfig,
) -> ExitCode {
    if !config.governance.enabled && !matches!(command, GovernanceCommands::Status { .. }) {
        eprintln!("Governance is not enabled. Add [governance] enabled = true to aphoria.toml");
        return ExitCode::from(1);
    }

    match command {
        GovernanceCommands::Pending { workflow, format } => {
            handle_pending(workflow.as_deref(), &format, config).await
        }
        GovernanceCommands::Approve { id, comment } => handle_approve(&id, comment, config).await,
        GovernanceCommands::Reject { id, reason } => handle_reject(&id, &reason, config).await,
        GovernanceCommands::Escalate { id } => handle_escalate(&id, config).await,
        GovernanceCommands::Status { pattern, all, format } => {
            handle_status(pattern.as_deref(), all, &format, config).await
        }
        GovernanceCommands::CheckTimeouts => handle_check_timeouts(config).await,
        GovernanceCommands::Create { pattern_id, workflow } => {
            handle_create(&pattern_id, workflow.as_deref(), config).await
        }
    }
}

/// Handle audit subcommands.
pub async fn handle_audit_command(command: AuditCommands, config: &AphoriaConfig) -> ExitCode {
    match command {
        AuditCommands::Trail { pattern, format } => handle_trail(&pattern, &format, config).await,
        AuditCommands::Export { output, format, date_range } => {
            handle_export(&output, &format, date_range.as_deref(), config).await
        }
        AuditCommands::Summary { format } => handle_summary(&format, config).await,
    }
}

/// List pending approval requests.
async fn handle_pending(
    workflow_filter: Option<&str>,
    format: &str,
    config: &AphoriaConfig,
) -> ExitCode {
    let sm = match GovernanceStateMachine::open_default(config.governance.clone()) {
        Ok(sm) => sm,
        Err(e) => {
            eprintln!("Failed to open governance store: {}", e);
            return ExitCode::from(1);
        }
    };

    // Check timeouts if configured
    if config.governance.check_timeouts_on_access {
        let _ = sm.check_timeouts();
    }

    let pending = match sm.list_pending() {
        Ok(p) => p,
        Err(e) => {
            eprintln!("Failed to list pending requests: {}", e);
            return ExitCode::from(1);
        }
    };

    // Filter by workflow if specified
    let filtered: Vec<_> = if let Some(wf) = workflow_filter {
        pending.into_iter().filter(|r| r.workflow_name == wf).collect()
    } else {
        pending
    };

    if filtered.is_empty() {
        println!("No pending approval requests.");
        return ExitCode::SUCCESS;
    }

    match format {
        "json" => {
            let json = serde_json::to_string_pretty(&filtered).unwrap_or_else(|_| "[]".to_string());
            println!("{}", json);
        }
        _ => {
            println!("Pending Approval Requests");
            println!("{}", "=".repeat(80));
            println!();
            println!("{:<36} {:<20} {:<15} {:<10}", "Request ID", "Pattern", "Stage", "Days");
            println!("{}", "-".repeat(80));

            for request in &filtered {
                let stage = request.status.current_stage().unwrap_or("-");
                let days = (Utc::now() - request.created_at).num_days();
                let pattern_name = truncate(&request.pattern_name, 20);

                println!("{:<36} {:<20} {:<15} {:<10}", request.id, pattern_name, stage, days);
            }

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

    ExitCode::SUCCESS
}

/// Approve a pending request.
async fn handle_approve(id: &str, comment: Option<String>, config: &AphoriaConfig) -> ExitCode {
    let request_id = match Uuid::parse_str(id) {
        Ok(id) => id,
        Err(e) => {
            eprintln!("Invalid request ID '{}': {}", id, e);
            return ExitCode::from(1);
        }
    };

    let sm = match GovernanceStateMachine::open_default(config.governance.clone()) {
        Ok(sm) => sm,
        Err(e) => {
            eprintln!("Failed to open governance store: {}", e);
            return ExitCode::from(1);
        }
    };

    let approver = whoami::username();

    match sm.approve(request_id, &approver, comment) {
        Ok(request) => {
            println!("Approved successfully");
            println!();
            println!("  Request ID: {}", request.id);
            println!("  Pattern:    {}", request.pattern_name);
            println!("  Status:     {}", request.status);

            if request.status.is_approved() {
                println!();
                println!("Workflow complete. Pattern can now be promoted.");
            }

            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("Failed to approve: {}", e);
            ExitCode::from(1)
        }
    }
}

/// Reject a pending request.
async fn handle_reject(id: &str, reason: &str, config: &AphoriaConfig) -> ExitCode {
    let request_id = match Uuid::parse_str(id) {
        Ok(id) => id,
        Err(e) => {
            eprintln!("Invalid request ID '{}': {}", id, e);
            return ExitCode::from(1);
        }
    };

    let sm = match GovernanceStateMachine::open_default(config.governance.clone()) {
        Ok(sm) => sm,
        Err(e) => {
            eprintln!("Failed to open governance store: {}", e);
            return ExitCode::from(1);
        }
    };

    let approver = whoami::username();

    match sm.reject(request_id, &approver, reason.to_string()) {
        Ok(request) => {
            println!("Request rejected");
            println!();
            println!("  Request ID: {}", request.id);
            println!("  Pattern:    {}", request.pattern_name);
            println!("  Reason:     {}", reason);
            println!();
            println!("Pattern promotion blocked. Create a new request to try again.");

            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("Failed to reject: {}", e);
            ExitCode::from(1)
        }
    }
}

/// Escalate a pending request.
async fn handle_escalate(id: &str, config: &AphoriaConfig) -> ExitCode {
    let request_id = match Uuid::parse_str(id) {
        Ok(id) => id,
        Err(e) => {
            eprintln!("Invalid request ID '{}': {}", id, e);
            return ExitCode::from(1);
        }
    };

    let sm = match GovernanceStateMachine::open_default(config.governance.clone()) {
        Ok(sm) => sm,
        Err(e) => {
            eprintln!("Failed to open governance store: {}", e);
            return ExitCode::from(1);
        }
    };

    let escalator = whoami::username();

    match sm.escalate(request_id, &escalator) {
        Ok(request) => {
            println!("Request escalated");
            println!();
            println!("  Request ID: {}", request.id);
            println!("  Pattern:    {}", request.pattern_name);
            println!("  Status:     {}", request.status);

            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("Failed to escalate: {}", e);
            ExitCode::from(1)
        }
    }
}

/// Show request status.
async fn handle_status(
    pattern_filter: Option<&str>,
    show_all: bool,
    format: &str,
    _config: &AphoriaConfig,
) -> ExitCode {
    let store = match GovernanceStore::open_default() {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open governance store: {}", e);
            return ExitCode::from(1);
        }
    };

    let requests = if let Some(pattern_str) = pattern_filter {
        match Uuid::parse_str(pattern_str) {
            Ok(pattern_id) => match store.get_request_by_pattern(&pattern_id) {
                Ok(Some(r)) => vec![r],
                Ok(None) => {
                    println!("No approval request found for pattern {}", pattern_str);
                    return ExitCode::SUCCESS;
                }
                Err(e) => {
                    eprintln!("Failed to get request: {}", e);
                    return ExitCode::from(1);
                }
            },
            Err(e) => {
                eprintln!("Invalid pattern ID '{}': {}", pattern_str, e);
                return ExitCode::from(1);
            }
        }
    } else if show_all {
        match store.list_all() {
            Ok(r) => r,
            Err(e) => {
                eprintln!("Failed to list requests: {}", e);
                return ExitCode::from(1);
            }
        }
    } else {
        match store.list_pending() {
            Ok(r) => r,
            Err(e) => {
                eprintln!("Failed to list pending: {}", e);
                return ExitCode::from(1);
            }
        }
    };

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

    match format {
        "json" => {
            let json = serde_json::to_string_pretty(&requests).unwrap_or_else(|_| "[]".to_string());
            println!("{}", json);
        }
        _ => {
            for request in &requests {
                print_request_details(request);
                println!();
            }
        }
    }

    ExitCode::SUCCESS
}

/// Print detailed request information.
fn print_request_details(request: &ApprovalRequest) {
    println!("Request: {}", request.id);
    println!("{}", "=".repeat(60));
    println!("  Pattern:    {} ({})", request.pattern_name, request.pattern_id);
    println!("  Workflow:   {}", request.workflow_name);
    println!("  Status:     {}", request.status);
    println!(
        "  Created:    {} by {}",
        request.created_at.format("%Y-%m-%d %H:%M"),
        request.created_by
    );
    println!("  Updated:    {}", request.updated_at.format("%Y-%m-%d %H:%M"));

    if let Some(deadline) = request.stage_deadline {
        let remaining = deadline - Utc::now();
        if remaining.num_seconds() > 0 {
            println!(
                "  Deadline:   {} ({} hours remaining)",
                deadline.format("%Y-%m-%d %H:%M"),
                remaining.num_hours()
            );
        } else {
            println!("  Deadline:   {} (OVERDUE)", deadline.format("%Y-%m-%d %H:%M"));
        }
    }

    if let Some(ref evidence) = request.evidence_summary {
        println!("  Evidence:   {}", evidence);
    }

    if !request.decisions.is_empty() {
        println!();
        println!("  Decisions:");
        for decision in &request.decisions {
            let comment = decision.comment.as_deref().unwrap_or("-");
            println!(
                "    {} {} by {} at {} ({})",
                decision.timestamp.format("%Y-%m-%d %H:%M"),
                decision.decision,
                decision.approver,
                decision.stage,
                comment
            );
        }
    }
}

/// Check and process timed-out requests.
async fn handle_check_timeouts(config: &AphoriaConfig) -> ExitCode {
    let sm = match GovernanceStateMachine::open_default(config.governance.clone()) {
        Ok(sm) => sm,
        Err(e) => {
            eprintln!("Failed to open governance store: {}", e);
            return ExitCode::from(1);
        }
    };

    match sm.check_timeouts() {
        Ok(processed) => {
            if processed.is_empty() {
                println!("No timed-out requests found.");
            } else {
                println!("Processed {} timed-out requests:", processed.len());
                println!();

                for request in &processed {
                    println!("  {} - {} - {}", request.id, request.pattern_name, request.status);
                }
            }

            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("Failed to check timeouts: {}", e);
            ExitCode::from(1)
        }
    }
}

/// Create an approval request for a pattern.
async fn handle_create(
    pattern_id_str: &str,
    workflow_name: Option<&str>,
    config: &AphoriaConfig,
) -> ExitCode {
    let pattern_id = match Uuid::parse_str(pattern_id_str) {
        Ok(id) => id,
        Err(e) => {
            eprintln!("Invalid pattern ID '{}': {}", pattern_id_str, 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);
        }
    };

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

    // Get workflow
    let workflow = if let Some(name) = workflow_name {
        match config.governance.get_workflow(name) {
            Some(w) => w.clone(),
            None => {
                eprintln!("Workflow '{}' not found", name);
                return ExitCode::from(1);
            }
        }
    } else {
        match config.governance.get_default_workflow() {
            Some(w) => w.clone(),
            None => {
                eprintln!("No default workflow configured");
                return ExitCode::from(1);
            }
        }
    };

    let sm = match GovernanceStateMachine::open_default(config.governance.clone()) {
        Ok(sm) => sm,
        Err(e) => {
            eprintln!("Failed to open governance store: {}", e);
            return ExitCode::from(1);
        }
    };

    let creator = whoami::username();

    match sm.create_request(&pattern, &workflow, &creator) {
        Ok(request) => {
            println!("Approval request created");
            println!();
            println!("  Request ID: {}", request.id);
            println!("  Pattern:    {}", request.pattern_name);
            println!("  Workflow:   {}", request.workflow_name);
            println!("  Status:     {}", request.status);

            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("Failed to create request: {}", e);
            ExitCode::from(1)
        }
    }
}

/// Show audit trail for a pattern.
async fn handle_trail(pattern_id_str: &str, format: &str, config: &AphoriaConfig) -> ExitCode {
    let _ = config; // Unused but kept for API consistency
    let pattern_id = match Uuid::parse_str(pattern_id_str) {
        Ok(id) => id,
        Err(e) => {
            eprintln!("Invalid pattern ID '{}': {}", pattern_id_str, e);
            return ExitCode::from(1);
        }
    };

    let trail = match AuditTrail::open_default() {
        Ok(t) => t,
        Err(e) => {
            eprintln!("Failed to open audit trail: {}", e);
            return ExitCode::from(1);
        }
    };

    let events = match trail.get_pattern_timeline(&pattern_id) {
        Ok(e) => e,
        Err(e) => {
            eprintln!("Failed to get timeline: {}", e);
            return ExitCode::from(1);
        }
    };

    if events.is_empty() {
        println!("No audit events for pattern {}", pattern_id_str);
        return ExitCode::SUCCESS;
    }

    match format {
        "json" => {
            let json = serde_json::to_string_pretty(&events).unwrap_or_else(|_| "[]".to_string());
            println!("{}", json);
        }
        _ => {
            println!("Audit Trail for {}", pattern_id_str);
            println!("{}", "=".repeat(70));
            println!();
            println!("{:<20} {:<20} {:<15} {:<15}", "Timestamp", "Event", "Actor", "Request");
            println!("{}", "-".repeat(70));

            for event in &events {
                println!(
                    "{:<20} {:<20} {:<15} {:<15}",
                    event.timestamp.format("%Y-%m-%d %H:%M"),
                    event.event_type.to_string(),
                    truncate(&event.actor, 15),
                    &event.request_id.to_string()[..8],
                );
            }

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

    ExitCode::SUCCESS
}

/// Export audit data.
async fn handle_export(
    output: &Path,
    format_str: &str,
    date_range: Option<&str>,
    _config: &AphoriaConfig,
) -> ExitCode {
    let format = match format_str.parse::<ExportFormat>() {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Invalid format: {}", e);
            return ExitCode::from(1);
        }
    };

    let trail = match AuditTrail::open_default() {
        Ok(t) => t,
        Err(e) => {
            eprintln!("Failed to open audit trail: {}", e);
            return ExitCode::from(1);
        }
    };

    let result = if let Some(range) = date_range {
        // Parse date range
        let parts: Vec<&str> = range.split("..").collect();
        if parts.len() != 2 {
            eprintln!("Invalid date range format. Use: YYYY-MM-DD..YYYY-MM-DD");
            return ExitCode::from(1);
        }

        let start = match NaiveDate::parse_from_str(parts[0], "%Y-%m-%d") {
            Ok(d) => Utc.from_utc_datetime(&d.and_hms_opt(0, 0, 0).unwrap_or_default()),
            Err(e) => {
                eprintln!("Invalid start date: {}", e);
                return ExitCode::from(1);
            }
        };

        let end = match NaiveDate::parse_from_str(parts[1], "%Y-%m-%d") {
            Ok(d) => Utc.from_utc_datetime(&d.and_hms_opt(23, 59, 59).unwrap_or_default()),
            Err(e) => {
                eprintln!("Invalid end date: {}", e);
                return ExitCode::from(1);
            }
        };

        trail.export_date_range(format, output, start, end)
    } else {
        trail.export(format, output)
    };

    match result {
        Ok(()) => {
            println!("Exported audit data to {}", output.display());
            ExitCode::SUCCESS
        }
        Err(e) => {
            eprintln!("Failed to export: {}", e);
            ExitCode::from(1)
        }
    }
}

/// Show audit summary.
async fn handle_summary(format: &str, _config: &AphoriaConfig) -> ExitCode {
    let store = match GovernanceStore::open_default() {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to open governance store: {}", e);
            return ExitCode::from(1);
        }
    };

    let trail = match AuditTrail::open_default() {
        Ok(t) => t,
        Err(e) => {
            eprintln!("Failed to open audit trail: {}", e);
            return ExitCode::from(1);
        }
    };

    let requests = match store.list_all() {
        Ok(r) => r,
        Err(e) => {
            eprintln!("Failed to list requests: {}", e);
            return ExitCode::from(1);
        }
    };

    let events = match trail.get_all_events() {
        Ok(e) => e,
        Err(e) => {
            eprintln!("Failed to get events: {}", e);
            return ExitCode::from(1);
        }
    };

    // Calculate statistics
    let total_requests = requests.len();
    let approved = requests.iter().filter(|r| r.status.is_approved()).count();
    let rejected = requests.iter().filter(|r| r.status.is_rejected()).count();
    let pending = requests.iter().filter(|r| r.status.is_pending()).count();
    let expired = requests.iter().filter(|r| matches!(r.status, ApprovalStatus::Expired)).count();

    let approval_rate =
        if total_requests > 0 { (approved as f32 / total_requests as f32) * 100.0 } else { 0.0 };

    // Calculate average approval time for completed requests
    let avg_approval_days: Option<f32> = {
        let completed: Vec<_> = requests.iter().filter(|r| r.status.is_approved()).collect();
        if completed.is_empty() {
            None
        } else {
            let total_days: i64 =
                completed.iter().map(|r| (r.updated_at - r.created_at).num_days()).sum();
            Some(total_days as f32 / completed.len() as f32)
        }
    };

    match format {
        "json" => {
            let summary = serde_json::json!({
                "total_requests": total_requests,
                "approved": approved,
                "rejected": rejected,
                "pending": pending,
                "expired": expired,
                "approval_rate_percent": approval_rate,
                "avg_approval_days": avg_approval_days,
                "total_events": events.len(),
            });
            let json = serde_json::to_string_pretty(&summary).unwrap_or_else(|_| "{}".to_string());
            println!("{}", json);
        }
        _ => {
            println!("Governance Audit Summary");
            println!("{}", "=".repeat(50));
            println!();
            println!("Requests:");
            println!("  Total:    {}", total_requests);
            println!("  Approved: {} ({:.1}%)", approved, approval_rate);
            println!("  Rejected: {}", rejected);
            println!("  Pending:  {}", pending);
            println!("  Expired:  {}", expired);
            println!();

            if let Some(days) = avg_approval_days {
                println!("Average approval time: {:.1} days", days);
            }

            println!("Total audit events: {}", events.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.saturating_sub(3)])
    }
}
