//! Development server command implementation

use std::collections::HashMap;
use std::path::Path;

use rustelo_core::{
    assets::{AssetCategory, AssetResolver},
    config::RusteloConfig,
    Result, RusteloError,
};
use tokio::signal;

/// Run the development server
pub async fn run(port: u16, watch: bool) -> Result<()> {
    tracing::info!("Starting development server on port {}", port);

    // Process assets for development
    let _processed_files = process_dev_assets().await?;

    if watch {
        tracing::info!("Hot reloading enabled");
        start_dev_server_with_watch(port).await
    } else {
        start_basic_dev_server(port).await
    }
}

/// Process assets for development mode
async fn process_dev_assets() -> Result<usize> {
    tracing::info!("Processing assets for development...");

    let config = RusteloConfig::load().unwrap_or_default();
    let resolver = AssetResolver::new(config);

    // Set up development variables
    let mut variables = HashMap::new();
    variables.insert("mode".to_string(), "development".to_string());
    variables.insert("hot_reload".to_string(), "true".to_string());
    variables.insert("timestamp".to_string(), chrono::Utc::now().to_rfc3339());

    // Development asset directory
    let dev_assets_dir = Path::new("target/dev/assets");

    // Process only development-relevant categories
    let dev_categories = vec![
        AssetCategory::Static,
        AssetCategory::Content,
        AssetCategory::Config,
        AssetCategory::Development,
    ];

    let processed = resolver
        .process_assets_by_category(dev_assets_dir, &dev_categories, variables)
        .await?;

    println!("📦 Development assets processed: {} files", processed.len());
    tracing::info!("Assets available at: {}", dev_assets_dir.display());

    Ok(processed.len())
}

/// Start basic development server without watching
async fn start_basic_dev_server(port: u16) -> Result<()> {
    println!("🚀 Development server running on http://localhost:{}", port);
    println!("📁 Assets served from: target/dev/assets/");
    println!("Press Ctrl+C to stop");

    // Wait for Ctrl+C signal
    match signal::ctrl_c().await {
        Ok(()) => {
            println!("\n🛑 Development server stopping...");
            Ok(())
        }
        Err(err) => {
            tracing::error!("Failed to listen for shutdown signal: {}", err);
            Err(RusteloError::generic(format!(
                "Signal handling error: {}",
                err
            )))
        }
    }
}

/// Start development server with file watching and hot reloading
async fn start_dev_server_with_watch(port: u16) -> Result<()> {
    println!(
        "🚀 Development server with hot reload on http://localhost:{}",
        port
    );
    println!("👀 Watching for asset changes...");
    println!("📁 Assets served from: target/dev/assets/");
    println!("Press Ctrl+C to stop");

    // TODO: Implement file watching with notify crate
    // For now, simulate by checking periodically
    let mut last_check = std::time::SystemTime::now();

    loop {
        tokio::select! {
            _ = signal::ctrl_c() => {
                println!("\n🛑 Development server stopping...");
                break;
            }
            _ = tokio::time::sleep(tokio::time::Duration::from_secs(2)) => {
                // Check if assets need reprocessing
                if should_rebuild_assets(last_check).await? {
                    println!("🔄 Assets changed, reprocessing...");
                    match process_dev_assets().await {
                        Ok(count) => {
                            println!("✅ Reprocessed {} assets", count);
                            last_check = std::time::SystemTime::now();
                        }
                        Err(e) => {
                            tracing::warn!("Asset reprocessing failed: {}", e);
                        }
                    }
                }
            }
        }
    }

    Ok(())
}

/// Check if assets need to be rebuilt based on file modification times
async fn should_rebuild_assets(last_check: std::time::SystemTime) -> Result<bool> {
    let config = RusteloConfig::load().unwrap_or_default();

    // Check if any source asset directories have been modified
    for asset_dir in [&config.paths.local_assets, &config.paths.framework_assets] {
        if asset_dir.exists() {
            if let Ok(metadata) = std::fs::metadata(asset_dir) {
                if let Ok(modified) = metadata.modified() {
                    if modified > last_check {
                        return Ok(true);
                    }
                }
            }
        }
    }

    Ok(false)
}
