use spvirit_scry::common::interfaces::{default_interface_index, find_interface_index, InterfaceInfo, InterfaceSelection};
use spvirit_scry::common::stats::IfStats;
use spvirit_scry::ui::tui::main_funcs;
use spvirit_scry::utils::common_version_print::version_header;
use spvirit_scry::utils::packet_processor::process_packets;

use argparse::{ArgumentParser, Store, StoreFalse, StoreTrue};
use std::sync::{Arc, Mutex};
use std::thread;
// use colored::Colorize;
use colored::*;
use tracing::{debug, info, Level};

fn list_interfaces() -> Vec<InterfaceInfo> {
    match pcap::Device::list() {
        Ok(devices) => devices
            .into_iter()
            .map(|dev| InterfaceInfo {
                name: dev.name,
                description: dev.desc.unwrap_or_default(),
            })
            .collect(),
        Err(err) => {
            eprintln!("Failed to list interfaces: {}", err);
            Vec::new()
        }
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut verbose = true;
    let mut show_payload = false;
    let mut exclude_cmds_str = String::new();
    let mut exclude_cmds: Vec<String> = Vec::new();
    let mut device = String::new();
    let mut integration_period = 1;
    let mut tui_mode = false;
    let mut debug_mode = false;
    let mut resolve = false;
    let mut buffer_size: usize = 5000;
    let mut version = false;
    let mut pva_ttl_secs: u64 = 300; // 5 minutes default
    let mut pva_max_channels: usize = 40_000;
    let mut tracked_only = false;
    let mut tui_tick_ms: u64 = 100;
    let mut pva_max_update_rate: usize = 10_000;

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Packet capture tool");
        ap.refer(&mut verbose)
            .add_option(&["-q", "--quiet"], StoreFalse, "Be quiet");
        ap.refer(&mut device)
            .add_option(&["-i", "--device"], Store, "Device to capture from");
        ap.refer(&mut integration_period).add_option(
            &["-t", "--integration-time"],
            Store,
            "Integration period in seconds",
        );
        ap.refer(&mut show_payload).add_option(
            &["-p", "--show-payload"],
            StoreTrue,
            "Show packet payload",
        );
        ap.refer(&mut exclude_cmds_str).add_option(
            &["-x", "--exclude-cmds"],
            Store,
            "Comma-separated PVA commands to exclude from display (e.g. PUT,MONITOR)",
        );
        ap.refer(&mut tui_mode)
            .add_option(&["-t", "--tui"], StoreTrue, "Show TUI");
        ap.refer(&mut debug_mode)
            .add_option(&["-d", "--debug"], StoreTrue, "Show debug messages");
        ap.refer(&mut resolve)
            .add_option(&["-r", "--resolve"], StoreTrue, "Resolve IP addresses");
        ap.refer(&mut buffer_size).add_option(
            &["-b", "--buffer-size"],
            Store,
            "Buffer size for packet capture 100 - 50000",
        );
        ap.refer(&mut version)
            .add_option(&["-v", "--version"], StoreTrue, "Show version and exit");
        ap.refer(&mut pva_ttl_secs).add_option(
            &["--pva-ttl"],
            Store,
            "PVA channel state TTL in seconds (default: 300)",
        );
        ap.refer(&mut pva_max_channels).add_option(
            &["--pva-max-channels"],
            Store,
            "Maximum PVA channels to track per connection (default: 40000)",
        );
        ap.refer(&mut tracked_only).add_option(
            &["--tracked-only"],
            StoreTrue,
            "Only show packets from tracked connections (where PV names are known)",
        );
        ap.refer(&mut tui_tick_ms).add_option(
            &["--tui-tick-ms"],
            Store,
            "TUI refresh interval in milliseconds (default: 100)",
        );
        ap.refer(&mut pva_max_update_rate).add_option(
            &["--pva-max-update-rate"],
            Store,
            "Maximum update timestamps kept for rate calculation (default: 10000)",
        );
        ap.parse_args_or_exit();
    }

    // parse exclude list into uppercased tokens
    if !exclude_cmds_str.trim().is_empty() {
        exclude_cmds = exclude_cmds_str
            .split(',')
            .map(|s| s.trim().to_uppercase())
            .filter(|s| !s.is_empty())
            .collect();
    }

    if version {
        version_header();
        std::process::exit(0);
    }

    let if_stats = Arc::new(Mutex::new(IfStats::new()));
    if resolve {
        let mut if_stats = if_stats.lock().unwrap();
        if_stats.enable_resolve();
    }
    if !(100..=50_000).contains(&buffer_size) {
        eprintln!("Buffer size must be between 100 and 50000");
        std::process::exit(1);
    } else {
        let mut if_stats = if_stats.lock().unwrap();
        if_stats.set_buffer_size(buffer_size);
    }

    let interfaces = list_interfaces();
    if interfaces.is_empty() {
        eprintln!("No capture interfaces found");
        std::process::exit(1);
    }

    let requested_device = device.trim().to_string();
    let selected_index = if requested_device.is_empty() {
        default_interface_index(&interfaces)
    } else {
        find_interface_index(&interfaces, &requested_device)
            .unwrap_or_else(|| default_interface_index(&interfaces))
    };
    let selected_name = interfaces
        .get(selected_index)
        .map(|iface| iface.name.clone())
        .unwrap_or_else(|| "".to_string());

    if !requested_device.is_empty() && requested_device != selected_name {
        eprintln!(
            "Requested interface '{}' not found, using '{}' instead",
            requested_device, selected_name
        );
    }

    let interface_selection = Arc::new(InterfaceSelection::new(interfaces, selected_index));
    let capture_device = selected_name;

    if verbose {
        if debug_mode {
            tracing_subscriber::fmt::fmt()
                .with_max_level(Level::DEBUG)
                .init();
        } else {
            tracing_subscriber::fmt::fmt()
                .with_max_level(Level::INFO)
                .init();
        }
        if !tui_mode {
            info!("Starting packet capture");
            info!("{}", format!("Using device {}", capture_device).green());
        }
    }

    let mut handles_vec = vec![];

    let mut if_stats_clone = Arc::clone(&if_stats);
    let interface_selection_capture = Arc::clone(&interface_selection);
    debug!("Starting packet processing thread");
    let handle_scan = thread::spawn(move || {
        process_packets(
            verbose,
            show_payload,
            &capture_device,
            integration_period,
            &mut if_stats_clone,
            exclude_cmds,
            pva_ttl_secs,
            pva_max_channels,
            tracked_only,
            pva_max_update_rate,
            Some(interface_selection_capture),
        );
    });
    handles_vec.push(handle_scan);
    debug!("Packet processing thread started");

    if tui_mode {
        debug!("Starting TUI thread");
        let mut if_stats_clone_tui = Arc::clone(&if_stats);
        let interface_selection_tui = Arc::clone(&interface_selection);
        let handle_tui = thread::spawn(move || {
            let _res = main_funcs(&mut if_stats_clone_tui, tui_tick_ms, Some(interface_selection_tui));
        });
        handles_vec.push(handle_tui);
        debug!("TUI thread started");
    }

    if verbose && !tui_mode {
        loop {
            thread::sleep(std::time::Duration::from_secs(1));

            if !show_payload {
                let if_stats = if_stats.lock().unwrap();
                let rate = if_stats.data_rate;
                let packet_rate = if_stats.packet_rate;
                let _timestamp = if_stats.timestamp.elapsed().as_secs();

                let str_rate = if rate > 1_000_000.0 {
                    format!("{:.2} Mb/s", rate / 1_000_000.0)
                } else if rate > 1_000.0 {
                    format!("{:.2} Kb/s", rate / 1_000.0)
                } else {
                    format!("{:.2} b/s", rate)
                };
                let str_packet_rate = format!("{:.2} pps", packet_rate);
                info!(
                    "{}",
                    format!("Data rate: {}, Packet rate: {}", str_rate, str_packet_rate).green()
                );

                for (k, v) in if_stats.source_ips.iter() {
                    info!("\tsource_ip: {} count: {}", k, v);
                }
                for (k, v) in if_stats.destination_ips.iter() {
                    info!("\tdestination_ip: {} count: {}", k, v);
                }
                for (k, v) in if_stats.request_types.iter() {
                    info!("\trequest_type:\t {:?} count: {:?}", k, v);
                }
            }
        }
    }

    for handle in handles_vec {
        handle.join().unwrap();
        debug!("Thread closed");
    }
    debug!("All threads closed");

    Ok(())
}
