//! Watch command - self-healing service monitor
//!
//! Continuously monitors service health and restarts failed services.

use anyhow::{Context, Result};
use colored::Colorize;
use std::collections::HashMap;
use std::process::Command;
use std::time::Duration;

use crate::config::{ForgeConfig, ServiceState};
use crate::state::find_project_root;

/// Run the watch command
pub async fn run(interval_secs: u64) -> Result<()> {
    println!("{}", "👁️ Starting self-healing watch mode...".bold());
    println!("   Press Ctrl+C to stop");
    println!();

    let project_root = find_project_root()?;
    let config = ForgeConfig::load(&project_root)?;

    // Track restart counts
    let mut restart_counts: HashMap<String, u32> = HashMap::new();

    loop {
        for (name, svc) in &config.services {
            if svc.state != ServiceState::Running {
                continue;
            }

            let is_healthy = check_health(name, &svc.health);

            if !is_healthy {
                let count = restart_counts.entry(name.clone()).or_insert(0);

                // Check if we've exceeded max restarts
                if svc.max_restarts > 0 && *count >= svc.max_restarts {
                    println!(
                        "{} {} exceeded max restarts ({}), skipping",
                        "⚠".yellow(),
                        name,
                        svc.max_restarts
                    );
                    continue;
                }

                if svc.auto_restart {
                    println!("{} {} unhealthy, restarting...", "🔄".cyan(), name);

                    // Wait before restart
                    tokio::time::sleep(Duration::from_secs(svc.restart_delay_secs)).await;

                    if let Err(e) = restart_service(name, &project_root) {
                        println!("{} Failed to restart {}: {}", "❌".red(), name, e);
                    } else {
                        *count += 1;
                        println!("{} {} restarted (attempt {})", "✅".green(), name, count);
                    }
                } else {
                    println!(
                        "{} {} is unhealthy (auto-restart disabled)",
                        "⚠".yellow(),
                        name
                    );
                }
            }
        }

        // Sleep until next check
        tokio::time::sleep(Duration::from_secs(interval_secs)).await;

        // Print heartbeat every 5 intervals
        print!(".");
        std::io::Write::flush(&mut std::io::stdout()).ok();
    }
}

fn check_health(name: &str, health: &Option<crate::config::HealthCheck>) -> bool {
    if let Some(h) = health {
        if let Some(ref url) = h.url {
            return Command::new("curl")
                .args(["-sf", "--max-time", &h.timeout_secs.to_string(), url])
                .output()
                .map(|o| o.status.success())
                .unwrap_or(false);
        }
        if let Some(port) = h.port {
            return std::net::TcpStream::connect(format!("127.0.0.1:{}", port)).is_ok();
        }
    }

    // Default health checks by service name
    let default_urls = [
        ("librechat", "http://localhost:3080"),
        ("oxigraph", "http://localhost:7878"),
        ("sea-api", "http://localhost:8080/health"),
    ];

    for (svc, url) in &default_urls {
        if name == *svc {
            return Command::new("curl")
                .args(["-sf", "--max-time", "5", url])
                .output()
                .map(|o| o.status.success())
                .unwrap_or(false);
        }
    }

    true // Unknown services are assumed healthy
}

fn restart_service(name: &str, project_root: &std::path::Path) -> Result<()> {
    let librechat_dir = project_root.join("deploy/librechat");

    match name {
        "librechat" | "sea-api" | "mongodb" | "meilisearch" => {
            Command::new("docker")
                .args(["compose", "restart", name])
                .current_dir(&librechat_dir)
                .output()
                .context(format!("Failed to restart {}", name))?;
        }
        "oxigraph" | "opa" => {
            // Restart skeleton services
            Command::new("just")
                .arg("skeleton-down")
                .current_dir(project_root)
                .output()?;
            Command::new("just")
                .arg("skeleton-up")
                .current_dir(project_root)
                .output()
                .context("Failed to restart skeleton services")?;
        }
        _ => {
            anyhow::bail!("Unknown service: {}", name);
        }
    }

    Ok(())
}
