use web_scraper::util::integrity::StateManager;
// src/main.rs - Cleaned up version with extracted helpers
use web_scraper::{*, scraper, corporate};
use crate::check_shutdown;
use anyhow::{Result};
use web_scraper::config::Config;
use scraper::docker_vpn_proxy::{DockerVpnProxyPool, cleanup_all_proxy_containers};
use scraper::webdriver::ChromeDriverPool;
use util::directories::DataPaths;
use util::{logger, opnv};
use std::fs::{OpenOptions};
use std::sync::Arc;
use std::sync::atomic::{AtomicBool, Ordering};
use std::process::Command;
use std::time::{Duration, Instant};

// ============================================================================
// HELPER FUNCTIONS - Extracted to reduce duplication
// ============================================================================

/// Start Docker Desktop on Windows
async fn start_docker_desktop() {
    if cfg!(target_os = "windows") {
        let _ = Command::new("cmd")
            .args(["/C", "docker desktop start"])
            .output();
    }
}

/// Shutdown ChromeDriver pool with error handling
async fn shutdown_chrome_pool(pool: &ChromeDriverPool) {
    logger::log_info("Shutting down ChromeDriver pool...").await;
    match pool.shutdown().await {
        Ok(()) => logger::log_info("✓ ChromeDriver pool shut down successfully").await,
        Err(e) => logger::log_error(&format!("✗ Pool shutdown error: {}", e)).await,
    }
}

/// Shutdown Docker VPN proxy pool with error handling
async fn shutdown_proxy_pool(proxy_pool: &DockerVpnProxyPool) {
    logger::log_info("Stopping Docker VPN proxy containers...").await;
    match proxy_pool.shutdown().await {
        Ok(()) => logger::log_info("✓ All Docker VPN containers stopped").await,
        Err(e) => logger::log_error(&format!("✗ Proxy shutdown error: {}", e)).await,
    }
}

/// Force-kill Chrome and ChromeDriver processes (Windows only)
#[cfg(target_os = "windows")]
async fn force_kill_chrome_processes() {
    logger::log_info("Force-killing any remaining Chrome processes...").await;
    let _ = tokio::process::Command::new("taskkill")
        .args(["/F", "/IM", "chrome.exe"])
        .output()
        .await;
    let _ = tokio::process::Command::new("taskkill")
        .args(["/F", "/IM", "chromedriver.exe"])
        .output()
        .await;
}

#[cfg(not(target_os = "windows"))]
async fn force_kill_chrome_processes() {
    // No-op on non-Windows platforms
}

/// Verify Chrome processes are cleaned up (Windows only)
#[cfg(target_os = "windows")]
async fn verify_chrome_cleanup() {
    if let Ok(output) = tokio::process::Command::new("tasklist")
        .args(["/FI", "IMAGENAME eq chrome.exe"])
        .output()
        .await
    {
        let stdout = String::from_utf8_lossy(&output.stdout);
        let chrome_count = stdout.lines().filter(|line| line.contains("chrome.exe")).count();
        
        if chrome_count > 0 {
            logger::log_warn(&format!("⚠️ {} Chrome processes still running after cleanup!", chrome_count)).await;
        } else {
            logger::log_info("✓ All Chrome processes cleaned up").await;
        }
    }
}

#[cfg(not(target_os = "windows"))]
async fn verify_chrome_cleanup() {
    // No-op on non-Windows platforms
}

/// Complete cleanup sequence: shutdown pools, cleanup containers, kill processes
async fn perform_full_cleanup(
    pool: &ChromeDriverPool,
    proxy_pool: Option<&DockerVpnProxyPool>,
) {
    shutdown_chrome_pool(pool).await;
    
    if let Some(pp) = proxy_pool {
        shutdown_proxy_pool(pp).await;
        cleanup_all_proxy_containers().await.ok();
    }
    
    force_kill_chrome_processes().await;
}

/// Create temporary ChromeDriver pool, fetch VPN credentials, and cleanup
async fn fetch_vpn_credentials_with_temp_pool(
    config: &Config,
    paths: &DataPaths,
    monitoring_handle: &monitoring::MonitoringHandle,
) -> Result<Option<Arc<DockerVpnProxyPool>>> {
    logger::log_info("VPN Rotation Enabled – Fetching latest VPNBook configs").await;
    
    // Create temp pool
    logger::log_info("Creating temporary ChromeDriver pool for VPN credential fetch...").await;
    let temp_pool = Arc::new(ChromeDriverPool::new_with_proxy_and_task_limit(
        None, 
        config, 
        Some(monitoring_handle.clone())
    ).await?);
    
    // Fetch credentials
    logger::log_info("Fetching VPNBook credentials...").await;
    let (username, password, _files) = opnv::fetch_vpnbook_configs(&temp_pool, paths.cache_dir()).await?;
    logger::log_info(&format!("VPNBook credentials → User: {}", username)).await;

    // Cleanup temp pool
    logger::log_info("Shutting down temporary pool...").await;
    match temp_pool.shutdown().await {
        Ok(()) => logger::log_info("✓ Temporary pool shut down successfully").await,
        Err(e) => {
            logger::log_error(&format!("✗ Temp pool shutdown error: {}", e)).await;
            force_kill_chrome_processes().await;
        }
    }
    
    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
    
    // Count VPN servers and create proxy pool
    let server_count = std::fs::read_dir(paths.cache_openvpn_dir())?
        .filter(|e| e.as_ref().unwrap().path().is_dir())
        .count();

    if server_count == 0 {
        logger::log_warn("No VPN servers found – continuing without VPN").await;
        return Ok(None);
    }
    
    logger::log_info(&format!("Found {} VPN servers – starting Docker proxy containers", server_count)).await;
    
    let number_proxy_instances = config.proxy_instances_per_certificate.unwrap_or(1);
    let proxy_pool = Arc::new(DockerVpnProxyPool::new(
        paths.cache_openvpn_dir(),
        username,
        password,
        number_proxy_instances
    ).await?);

    logger::log_info(&format!("All {} Docker proxy containers started and ready", proxy_pool.num_proxies())).await;
    
    // Emit proxy connection events
    for i in 0..proxy_pool.num_proxies() {
        if let Some(proxy_info) = proxy_pool.get_proxy_info(i) {
            monitoring_handle.emit(monitoring::MonitoringEvent::ProxyConnected {
                container_name: proxy_info.container_name.clone(),
                ip_address: proxy_info.ip_address.clone(),
                port: proxy_info.port,
            });
        }
    }

    Ok(Some(proxy_pool))
}

/// Initialize monitoring system
async fn initialize_monitoring(
    config: &Config,
    paths: &DataPaths,
) -> Result<(monitoring::MonitoringHandle, tokio::task::JoinHandle<()>)> {
    let config_snapshot = ConfigSnapshot {
        max_parallel_instances: config.max_parallel_instances,
        max_tasks_per_instance: config.max_tasks_per_instance,
        enable_vpn_rotation: config.enable_vpn_rotation,
        max_requests_per_session: config.max_requests_per_session,
        min_request_interval_ms: config.min_request_interval_ms,
        max_retry_attempts: config.max_retry_attempts,
    };

    let (monitoring_handle, monitoring_task) = init_monitoring(
        config_snapshot,
        paths.logs_dir().to_path_buf(),
        3030,
    ).await?;

    monitoring_handle.emit(monitoring::MonitoringEvent::PoolInitialized {
        pool_size: config.max_parallel_instances,
        with_proxy: config.enable_vpn_rotation,
        with_rotation: config.max_tasks_per_instance > 0,
    });

    logger::log_info("Monitoring dashboard available at http://localhost:3030").await;
    
    Ok((monitoring_handle, monitoring_task))
}

/// Setup Ctrl+C handler for graceful shutdown
fn setup_shutdown_handler(
    shutdown_flag: Arc<AtomicBool>,
    pool: Arc<ChromeDriverPool>,
    proxy_pool: Option<Arc<DockerVpnProxyPool>>,
) {
    tokio::spawn(async move {
        tokio::signal::ctrl_c().await.ok();
        logger::log_info("Ctrl+C received – shutting down gracefully...").await;
        
        shutdown_flag.store(true, Ordering::SeqCst);
        tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;

        perform_full_cleanup(&pool, proxy_pool.as_deref()).await;
        
        logger::log_info("Shutdown complete").await;
        std::process::exit(0);
    });
}

fn format_duration(duration: Duration) -> String {
    let total_seconds = duration.as_secs();
    
    let days = total_seconds / 86400;
    let hours = (total_seconds % 86400) / 3600;
    let minutes = (total_seconds % 3600) / 60;
    let seconds = total_seconds % 60;
    
    format!("{:02}::{:02}::{:02}::{:02}", days, hours, minutes, seconds)
}

async fn create_state_file(paths: &DataPaths) -> Result<()> {
    let integrity_path = paths.integrity_dir().join("state.jsonl");

    // Use OpenOptions to create the file only if it doesn't exist
    OpenOptions::new()
        .create(true)  // Create if it doesn't exist
        .write(true)   // Ensure we can write to the file
        .open(&integrity_path)?;
    logger::log_info(&format!("Checked or created file: {}", integrity_path.display())).await;

    Ok(())
}

async fn visualize_checkpoint_dependencies(paths: &DataPaths) -> Result<()> {
    // Add more detailed error handling
    match StateManager::new(
        paths.integrity_dir(),
    ).await {
        Ok(manager) => {
            logger::log_info("✓ Dependency configuration loaded successfully").await;
            manager.print_dependency_graph();
            
            let dot = manager.get_dependency_config().to_dot();
            let dot_path = paths.integrity_dir().join("checkpoint_dependencies.dot");
            std::fs::write(&dot_path, dot)?;
            
            logger::log_info(&format!("✓ DOT file written to: {}", dot_path.display())).await;
            Ok(())
        }
        Err(e) => {
            logger::log_error(&format!("✗ Failed to load dependency config: {}", e)).await;
            Err(e)
        }
    }
}

// ============================================================================
// MAIN FUNCTION - Simplified with extracted helpers
// ============================================================================

#[tokio::main]
async fn main() -> Result<()> {
    // Initial setup
    let start = Instant::now();
    let paths = DataPaths::new(".")?;

    start_docker_desktop().await;
    cleanup_all_proxy_containers().await.ok();
    create_state_file(&paths).await.ok();
    visualize_checkpoint_dependencies(&paths).await.ok();

    let config = Config::load().unwrap_or_else(|_| {
        eprintln!("Using default configuration");
        Config::default()
    });

    // Initialize monitoring
    let (monitoring_handle, _monitoring_task) = initialize_monitoring(&config, &paths).await?;

    // Initialize debug logger
    logger::init_debug_logger(paths.logs_dir()).await.ok();
    logger::log_info("=== Economic Webscraper Started ===").await;
    logger::log_info(&format!(
        "Config → parallel_instances: {}, task_limit: {}, vpn_rotation: {}, proxy_instances_per_certificate: {:?}",
        config.max_parallel_instances,
        config.max_tasks_per_instance,
        config.enable_vpn_rotation,
        config.proxy_instances_per_certificate
    )).await;

    let shutdown_flag = Arc::new(AtomicBool::new(false));

    // Fetch VPN credentials and setup proxy pool if enabled
    let proxy_pool = if config.enable_vpn_rotation {
        fetch_vpn_credentials_with_temp_pool(&config, &paths, &monitoring_handle).await?
    } else {
        logger::log_info("VPN rotation disabled – using direct connection").await;
        None
    };

    // Create main ChromeDriver pool
    logger::log_info(&format!("Creating ChromeDriver pool with {} instances...", config.max_parallel_instances)).await;
    
    let pool = Arc::new(ChromeDriverPool::new_with_proxy_and_task_limit(
        proxy_pool.clone(),
        &config,
        Some(monitoring_handle.clone())
    ).await?);

    logger::log_info(&format!("ChromeDriver pool ready with {} instances", config.max_parallel_instances)).await;

    // Setup Ctrl+C handler
    setup_shutdown_handler(
        Arc::clone(&shutdown_flag),
        Arc::clone(&pool),
        proxy_pool.clone(),
    );
    
    // Run scraping jobs
    check_shutdown!(&shutdown_flag);

    logger::log_info("--- Starting ECONOMIC data update ---").await;
    economic::run_full_update(&config, &pool, &shutdown_flag).await?;
    logger::log_info("Economic update completed").await;

    check_shutdown!(&shutdown_flag);

    logger::log_info("--- Starting CORPORATE data update ---").await;
    corporate::run_full_update(&config, &pool, &shutdown_flag).await?;
    logger::log_info("Corporate update completed").await;

    check_shutdown!(&shutdown_flag);

    // Final cleanup if not already shutting down
    perform_full_cleanup(&pool, proxy_pool.as_deref()).await;
    verify_chrome_cleanup().await;

    logger::log_info(&format!("=== Application finished after {} ===", format_duration(start.elapsed()))).await;    

    logger::log_info("=== Application finished successfully ===").await;    

    Ok(())
}