use anyhow::Result;
use arboard::Clipboard;
use log::{LevelFilter, debug, error, info, warn};
use ratatui::prelude::CrosstermBackend;
use simplelog::{Config as LogConfig, WriteLogger};
use std::fs::{self, File};
use std::io;
use std::path::Path;
use std::time::Duration;

mod app;
mod cli;
mod filter;
mod network;
mod ui;

fn main() -> Result<()> {
    // Check for required dependencies on Windows
    #[cfg(target_os = "windows")]
    check_windows_dependencies()?;

    // Parse command line arguments
    let matches = cli::build_cli().get_matches();

    // Set up logging only if log-level was provided
    if let Some(log_level_str) = matches.get_one::<String>("log-level") {
        let log_level = log_level_str
            .parse::<LevelFilter>()
            .map_err(|_| anyhow::anyhow!("Invalid log level: {}", log_level_str))?;
        setup_logging(log_level)?;
    }

    // Check privileges BEFORE initializing TUI (so error messages are visible)
    check_privileges_early()?;

    info!("Starting RustNet Monitor");

    // Build configuration from command line arguments
    let mut config = app::Config::default();

    if let Some(interface) = matches.get_one::<String>("interface") {
        config.interface = Some(interface.to_string());
        info!("Using interface: {}", interface);
    }

    if matches.get_flag("no-localhost") {
        config.filter_localhost = true;
        info!("Filtering localhost connections");
    }

    if matches.get_flag("show-localhost") {
        config.filter_localhost = false;
        info!("Showing localhost connections");
    }

    if let Some(interval) = matches.get_one::<u64>("refresh-interval") {
        config.refresh_interval = *interval;
        info!("Using refresh interval: {}ms", interval);
    }

    if matches.get_flag("no-dpi") {
        config.enable_dpi = false;
        info!("Deep packet inspection disabled");
    }

    if let Some(json_log_path) = matches.get_one::<String>("json-log") {
        config.json_log_file = Some(json_log_path.to_string());
        info!("JSON logging enabled: {}", json_log_path);
    }

    if let Some(pcap_path) = matches.get_one::<String>("pcap-export") {
        config.pcap_export_file = Some(pcap_path.to_string());
        info!("PCAP export enabled: {}", pcap_path);
    }

    if let Some(bpf_filter) = matches.get_one::<String>("bpf-filter") {
        let filter = bpf_filter.trim();
        if !filter.is_empty() {
            config.bpf_filter = Some(filter.to_string());
            info!("Using BPF filter: {}", filter);
        }
    }

    if matches.get_flag("no-resolve-dns") {
        config.resolve_dns = false;
        info!("Reverse DNS resolution disabled");
    }

    if matches.get_flag("show-ptr-lookups") {
        config.show_ptr_lookups = true;
        info!("PTR lookup connections will be shown in UI");
    }

    // Check NO_COLOR environment variable and --no-color flag (https://no-color.org)
    let no_color =
        matches.get_flag("no-color") || std::env::var("NO_COLOR").is_ok_and(|v| !v.is_empty());
    if no_color {
        info!("Colors disabled (NO_COLOR)");
        ui::set_no_color(true);
    }

    // GeoIP configuration
    if matches.get_flag("no-geoip") {
        config.disable_geoip = true;
        info!("GeoIP lookups disabled");
    }

    if let Some(country_path) = matches.get_one::<String>("geoip-country") {
        config.geoip_country_path = Some(country_path.to_string());
        info!("Using GeoIP Country database: {}", country_path);
    }

    if let Some(asn_path) = matches.get_one::<String>("geoip-asn") {
        config.geoip_asn_path = Some(asn_path.to_string());
        info!("Using GeoIP ASN database: {}", asn_path);
    }

    if let Some(city_path) = matches.get_one::<String>("geoip-city") {
        config.geoip_city_path = Some(city_path.to_string());
        info!("Using GeoIP City database: {}", city_path);
    }

    // Set up terminal
    let backend = CrosstermBackend::new(io::stdout());
    let mut terminal = ui::setup_terminal(backend)?;
    info!("Terminal UI initialized");

    // Create and start the application
    let mut app = app::App::new(config.clone())?;
    let process_ready_rx = app.start()?;
    info!("Application started");

    // Pre-create sidecar JSONL file for PCAP export (needed for Landlock permissions)
    // This must be done BEFORE Landlock is applied so the file exists when adding rules
    if let Some(ref pcap_path) = config.pcap_export_file {
        let jsonl_path = format!("{}.connections.jsonl", pcap_path);
        match std::fs::File::create(&jsonl_path) {
            Ok(_f) => {
                #[cfg(unix)]
                {
                    use std::os::unix::fs::PermissionsExt;
                    if let Err(e) = _f.set_permissions(std::fs::Permissions::from_mode(0o600)) {
                        warn!("Failed to set sidecar JSONL file permissions: {}", e);
                    }
                }
            }
            Err(e) => {
                warn!("Failed to pre-create sidecar JSONL file: {}", e);
            }
        }
    }

    // Wait for process detection (including eBPF loading) to complete before
    // applying the sandbox, which drops CAP_BPF and CAP_PERFMON.
    // Without this synchronization, the sandbox could drop these capabilities
    // before the background thread has finished loading eBPF programs.
    match process_ready_rx.recv_timeout(std::time::Duration::from_secs(10)) {
        Ok(()) => info!("Process detection initialized, safe to apply sandbox"),
        Err(std::sync::mpsc::RecvTimeoutError::Timeout) => {
            warn!("Timed out waiting for process detection init, applying sandbox anyway");
        }
        Err(std::sync::mpsc::RecvTimeoutError::Disconnected) => {
            warn!("Process detection thread exited early, applying sandbox anyway");
        }
    }

    // Apply Landlock sandbox (Linux only)
    // This must be done AFTER process detection is initialized because:
    // - eBPF programs need to be loaded first (requires CAP_BPF + CAP_PERFMON)
    // - Packet capture handles need to be opened first (access to /dev)
    // - Log files need to be created first
    #[cfg(all(target_os = "linux", feature = "landlock"))]
    {
        use network::geoip::GeoIpResolver;
        use network::platform::sandbox::{
            SandboxConfig, SandboxMode, SandboxStatus, apply_sandbox,
        };
        use std::path::PathBuf;

        let sandbox_mode = if matches.get_flag("no-sandbox") {
            SandboxMode::Disabled
        } else if matches.get_flag("sandbox-strict") {
            SandboxMode::Strict
        } else {
            SandboxMode::BestEffort
        };

        // Collect read paths (GeoIP databases)
        let read_paths: Vec<PathBuf> = GeoIpResolver::get_search_paths()
            .into_iter()
            .filter(|p| p.exists())
            .collect();

        let mut write_paths = Vec::new();

        // Add logs directory if logging is enabled
        if matches.get_one::<String>("log-level").is_some() {
            write_paths.push(PathBuf::from("logs"));
        }

        // Add JSON log path if specified
        if let Some(json_log_path) = &config.json_log_file {
            write_paths.push(PathBuf::from(json_log_path));
        }

        // Add PCAP export paths if specified (both .pcap and .pcap.connections.jsonl)
        if let Some(pcap_path) = &config.pcap_export_file {
            write_paths.push(PathBuf::from(pcap_path));
            write_paths.push(PathBuf::from(format!("{}.connections.jsonl", pcap_path)));
        }

        let sandbox_config = SandboxConfig {
            mode: sandbox_mode,
            block_network: true, // RustNet is passive, doesn't need TCP
            read_paths,
            write_paths,
        };

        match apply_sandbox(&sandbox_config) {
            Ok(result) => {
                // Update UI with sandbox status
                let status_str = match result.status {
                    SandboxStatus::FullyEnforced => "Fully enforced",
                    SandboxStatus::PartiallyEnforced => "Partially enforced",
                    SandboxStatus::NotApplied => "Not applied",
                };

                app.set_sandbox_info(app::SandboxInfo {
                    status: status_str.to_string(),
                    cap_dropped: result.cap_net_raw_dropped,
                    ebpf_caps_dropped: result.ebpf_caps_dropped,
                    landlock_available: result.landlock_available,
                    fs_restricted: result.landlock_fs_applied,
                    net_restricted: result.landlock_net_applied,
                });
            }
            Err(e) => {
                if sandbox_mode == SandboxMode::Strict {
                    return Err(e.context("Sandbox enforcement required but failed"));
                }
                warn!("Sandbox application error (non-strict mode): {}", e);
                app.set_sandbox_info(app::SandboxInfo {
                    status: "Error".to_string(),
                    cap_dropped: false,
                    ebpf_caps_dropped: false,
                    landlock_available: false,
                    fs_restricted: false,
                    net_restricted: false,
                });
            }
        }
    }

    // Apply Seatbelt sandbox (macOS only)
    // This must be done AFTER app.start() because:
    // - Packet capture handles need to be opened first (BPF/PKTAP fds survive the sandbox)
    // - Log files need to be created first
    #[cfg(all(target_os = "macos", feature = "macos-sandbox"))]
    {
        use network::platform::sandbox::{
            SandboxConfig, SandboxMode, SandboxStatus, apply_sandbox,
        };

        let sandbox_mode = if matches.get_flag("no-sandbox") {
            SandboxMode::Disabled
        } else if matches.get_flag("sandbox-strict") {
            SandboxMode::Strict
        } else {
            SandboxMode::BestEffort
        };

        let log_dir = if matches.get_one::<String>("log-level").is_some() {
            Some("logs".to_string())
        } else {
            None
        };

        // Collect GeoIP paths that may need read access through the sandbox.
        // User-specified paths take priority; otherwise include auto-discovery
        // search paths so the file-read deny on /Users doesn't block them.
        let geoip_paths: Vec<String> = {
            use network::geoip::GeoIpResolver;
            let mut paths = Vec::new();
            if let Some(ref p) = config.geoip_country_path {
                paths.push(p.clone());
            }
            if let Some(ref p) = config.geoip_asn_path {
                paths.push(p.clone());
            }
            if let Some(ref p) = config.geoip_city_path {
                paths.push(p.clone());
            }
            if paths.is_empty() && !config.disable_geoip {
                // Use auto-discovery search paths (directories, not individual files)
                paths.extend(
                    GeoIpResolver::get_search_paths()
                        .into_iter()
                        .filter(|p| p.exists())
                        .map(|p| p.to_string_lossy().into_owned()),
                );
            }
            paths
        };

        let sandbox_config = SandboxConfig {
            mode: sandbox_mode,
            block_network: true, // RustNet is passive, doesn't need TCP
            log_dir,
            json_log_path: config.json_log_file.clone(),
            pcap_export_path: config.pcap_export_file.clone(),
            geoip_paths,
        };

        match apply_sandbox(&sandbox_config) {
            Ok(result) => {
                let status_str = match result.status {
                    SandboxStatus::FullyEnforced => {
                        info!("Seatbelt sandbox fully enforced: {}", result.message);
                        "Fully enforced"
                    }
                    SandboxStatus::NotApplied => {
                        warn!("Seatbelt sandbox not applied: {}", result.message);
                        "Not applied"
                    }
                };

                app.set_sandbox_info(app::SandboxInfo {
                    status: status_str.to_string(),
                    seatbelt_applied: result.seatbelt_applied,
                    fs_restricted: result.fs_restricted,
                    net_restricted: result.net_blocked,
                });
            }
            Err(e) => {
                if sandbox_mode == SandboxMode::Strict {
                    return Err(e.context("Seatbelt sandbox enforcement required but failed"));
                }
                info!("Seatbelt sandbox error (non-strict mode): {}", e);
                app.set_sandbox_info(app::SandboxInfo {
                    status: "Error".to_string(),
                    seatbelt_applied: false,
                    fs_restricted: false,
                    net_restricted: false,
                });
            }
        }
    }

    // Apply restricted token sandbox (Windows only)
    // This must be done AFTER app.start() because:
    // - Npcap handles need to be opened first
    // - Log files need to be created first
    #[cfg(target_os = "windows")]
    {
        use network::platform::sandbox::{
            SandboxConfig, SandboxMode, SandboxStatus, apply_sandbox,
        };

        let sandbox_mode = if matches.get_flag("no-sandbox") {
            SandboxMode::Disabled
        } else if matches.get_flag("sandbox-strict") {
            SandboxMode::Strict
        } else {
            SandboxMode::BestEffort
        };

        let sandbox_config = SandboxConfig { mode: sandbox_mode };

        match apply_sandbox(&sandbox_config) {
            Ok(result) => {
                let status_str = match result.status {
                    SandboxStatus::FullyEnforced => {
                        info!("Windows sandbox fully enforced: {}", result.message);
                        "Fully enforced"
                    }
                    SandboxStatus::PartiallyEnforced => {
                        warn!("Windows sandbox partially enforced: {}", result.message);
                        "Partially enforced"
                    }
                    SandboxStatus::NotApplied => {
                        warn!("Windows sandbox not applied: {}", result.message);
                        "Not applied"
                    }
                };

                app.set_sandbox_info(app::SandboxInfo {
                    status: status_str.to_string(),
                    privileges_removed: result.privileges_removed,
                    privileges_removed_count: result.privileges_removed_count,
                    job_object_applied: result.job_object_applied,
                });
            }
            Err(e) => {
                if sandbox_mode == SandboxMode::Strict {
                    return Err(e.context("Windows sandbox enforcement required but failed"));
                }
                warn!("Windows sandbox error (non-strict mode): {}", e);
                app.set_sandbox_info(app::SandboxInfo {
                    status: "Error".to_string(),
                    privileges_removed: false,
                    privileges_removed_count: 0,
                    job_object_applied: false,
                });
            }
        }
    }

    // Run the UI loop
    let res = run_ui_loop(&mut terminal, &app);

    // Cleanup
    app.stop();
    ui::restore_terminal(&mut terminal)?;

    // Return any error that occurred
    if let Err(err) = res {
        error!("Application error: {}", err);
        println!("Error: {}", err);
    }

    info!("RustNet Monitor shutting down");
    Ok(())
}

fn setup_logging(level: LevelFilter) -> Result<()> {
    // Create logs directory if it doesn't exist
    let log_dir = Path::new("logs");
    if !log_dir.exists() {
        fs::create_dir_all(log_dir)?;
    }

    // Create timestamped log file name
    let timestamp = chrono::Local::now().format("%Y-%m-%d_%H-%M-%S");
    let log_file_path = log_dir.join(format!("rustnet_{}.log", timestamp));

    // Initialize the logger
    WriteLogger::init(level, LogConfig::default(), File::create(log_file_path)?)?;

    Ok(())
}

/// Sort connections based on the specified column and direction
fn sort_connections(
    connections: &mut [network::types::Connection],
    sort_column: ui::SortColumn,
    ascending: bool,
) {
    use ui::SortColumn;

    connections.sort_by(|a, b| {
        let ordering = match sort_column {
            SortColumn::CreatedAt => a.created_at.cmp(&b.created_at),

            SortColumn::BandwidthTotal => {
                // Compare combined up+down bandwidth, handle NaN cases
                let a_total = a.current_incoming_rate_bps + a.current_outgoing_rate_bps;
                let b_total = b.current_incoming_rate_bps + b.current_outgoing_rate_bps;
                a_total
                    .partial_cmp(&b_total)
                    .unwrap_or(std::cmp::Ordering::Equal)
            }

            SortColumn::Process => {
                let a_process = a.process_name.as_deref().unwrap_or("");
                let b_process = b.process_name.as_deref().unwrap_or("");
                a_process.cmp(b_process)
            }

            SortColumn::LocalAddress => a
                .local_addr
                .ip()
                .cmp(&b.local_addr.ip())
                .then_with(|| a.local_addr.port().cmp(&b.local_addr.port())),

            SortColumn::RemoteAddress => a
                .remote_addr
                .ip()
                .cmp(&b.remote_addr.ip())
                .then_with(|| a.remote_addr.port().cmp(&b.remote_addr.port())),

            SortColumn::Application => {
                let a_app = a.dpi_info.as_ref().map(|dpi| dpi.application.sort_key());
                let b_app = b.dpi_info.as_ref().map(|dpi| dpi.application.sort_key());
                a_app.cmp(&b_app)
            }

            SortColumn::Service => {
                let a_service = a.service_name.as_deref().unwrap_or("");
                let b_service = b.service_name.as_deref().unwrap_or("");
                a_service.cmp(b_service)
            }

            SortColumn::State => Ord::cmp(&a.state(), &b.state()),

            SortColumn::Location => {
                let a_loc = a
                    .geoip_info
                    .as_ref()
                    .and_then(|g| g.country_code.as_deref())
                    .unwrap_or("");
                let b_loc = b
                    .geoip_info
                    .as_ref()
                    .and_then(|g| g.country_code.as_deref())
                    .unwrap_or("");
                a_loc.cmp(b_loc)
            }

            SortColumn::Protocol => a.protocol.cmp(&b.protocol),
        };

        if ascending {
            ordering
        } else {
            ordering.reverse()
        }
    });
}

/// Copy text to the system clipboard and update UI state with feedback.
fn copy_to_clipboard(text: &str, display_msg: &str, ui_state: &mut ui::UIState, app: &app::App) {
    // Used conditionally on Linux/FreeBSD for sandbox-aware error messages
    let _ = app;
    let result = Clipboard::new().and_then(|mut cb| cb.set_text(text));

    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
    let result = result.or_else(|_| {
        std::process::Command::new("wl-copy")
            .arg(text)
            .status()
            .map_err(|e| arboard::Error::Unknown {
                description: e.to_string(),
            })
            .and_then(|s| {
                if s.success() {
                    Ok(())
                } else {
                    Err(arboard::Error::Unknown {
                        description: "wl-copy failed".to_string(),
                    })
                }
            })
    });

    match result {
        Ok(()) => {
            info!("Copied to clipboard: {}", display_msg);
            ui_state.clipboard_message = Some((
                format!("Copied: {}", display_msg),
                std::time::Instant::now(),
            ));
        }
        Err(e) => {
            #[cfg(target_os = "linux")]
            let msg = if app.get_sandbox_info().fs_restricted {
                "Clipboard unavailable (sandbox active). Use --no-sandbox to enable.".to_string()
            } else {
                format!("Clipboard error: {}", e)
            };
            #[cfg(not(target_os = "linux"))]
            let msg = format!("Clipboard error: {}", e);

            error!("{}", msg);
            ui_state.clipboard_message = Some((msg, std::time::Instant::now()));
        }
    }
}

fn run_ui_loop<B: ratatui::prelude::Backend>(
    terminal: &mut ui::Terminal<B>,
    app: &app::App,
) -> Result<()>
where
    <B as ratatui::prelude::Backend>::Error: Send + Sync + 'static,
{
    let tick_rate = Duration::from_millis(200);
    let mut last_tick = std::time::Instant::now();
    let mut ui_state = ui::UIState::default();
    let (has_country_db, _, _) = app.get_geoip_status();
    ui_state.has_geoip = has_country_db;
    let mut click_regions = ui::ClickableRegions::default();

    // Data state persists across loop iterations — only refreshed on timer tick
    // or when an event changes the underlying data (filter, sort, historic toggle, etc.)
    let mut connections: Vec<network::types::Connection> = Vec::new();
    let mut grouped_rows: Vec<ui::GroupedRow<'_>> = Vec::new();
    let mut stats = app.get_stats();
    let mut needs_data_refresh = true;
    let mut needs_regroup = false;

    loop {
        // Refresh connection data only when needed:
        // - On timer tick (every 200ms) for live updates
        // - When an event changes filter, sort, or data source
        if needs_data_refresh || last_tick.elapsed() >= tick_rate {
            connections = if ui_state.filter_query.is_empty() && !ui_state.filter_mode {
                app.get_connections()
            } else {
                app.get_filtered_connections(&ui_state.filter_query)
            };
            sort_connections(
                &mut connections,
                ui_state.sort_column,
                ui_state.sort_ascending,
            );
            grouped_rows = if ui_state.grouping_enabled {
                ui::compute_grouped_rows(&connections, &ui_state.expanded_groups)
            } else {
                Vec::new()
            };
            stats = app.get_stats();
            last_tick = std::time::Instant::now();
            needs_data_refresh = false;
            needs_regroup = false;
        } else if needs_regroup {
            // Only rebuild grouped rows from existing connections
            // (e.g., after expand/collapse or grouping toggle)
            grouped_rows = if ui_state.grouping_enabled {
                ui::compute_grouped_rows(&connections, &ui_state.expanded_groups)
            } else {
                Vec::new()
            };
            needs_regroup = false;
        }

        // Ensure we have a valid selection (handles connection removals)
        if ui_state.grouping_enabled {
            ui_state.ensure_valid_grouped_selection(&grouped_rows);
            let selected_idx = ui_state
                .get_selected_grouped_index(&grouped_rows)
                .unwrap_or(0);
            ui_state.grouped_scroll_offset = ui::compute_scroll_offset(
                selected_idx,
                ui_state.grouped_scroll_offset,
                ui_state.visible_rows,
                grouped_rows.len(),
            );
        } else {
            ui_state.ensure_valid_selection(&connections);
            let selected_idx = ui_state.get_selected_index(&connections).unwrap_or(0);
            ui_state.scroll_offset = ui::compute_scroll_offset(
                selected_idx,
                ui_state.scroll_offset,
                ui_state.visible_rows,
                connections.len(),
            );
        }

        // Draw the UI
        terminal.draw(|f| {
            let grouped = if ui_state.grouping_enabled {
                Some(grouped_rows.as_slice())
            } else {
                None
            };
            if let Err(err) = ui::draw(
                f,
                app,
                &ui_state,
                &connections,
                grouped,
                &stats,
                &mut click_regions,
            ) {
                error!("UI draw error: {}", err);
            }
        })?;

        // Update visible rows for page navigation based on terminal height
        if let Ok(size) = terminal.size() {
            let chrome = if ui_state.filter_mode || !ui_state.filter_query.is_empty() {
                11
            } else {
                8
            };
            ui_state.visible_rows = (size.height as usize).saturating_sub(chrome);
        }

        // Handle timeout for periodic updates
        let timeout = tick_rate
            .checked_sub(last_tick.elapsed())
            .unwrap_or(Duration::from_secs(0));

        // Clear clipboard message after timeout
        if let Some((_, time)) = &ui_state.clipboard_message
            && time.elapsed().as_secs() >= 3
        {
            ui_state.clipboard_message = None;
        }

        // Handle input events
        if crossterm::event::poll(timeout)? {
            let event = crossterm::event::read()?;
            match event {
                crossterm::event::Event::Mouse(mouse) => {
                    use crossterm::event::{MouseButton, MouseEventKind};

                    match mouse.kind {
                        MouseEventKind::Down(MouseButton::Left) => {
                            ui_state.quit_confirmation = false;
                            ui_state.clear_confirmation = false;

                            // Detect double-click (two clicks within 400ms at the same row)
                            let is_double_click =
                                if let Some((_, prev_row, prev_time)) = ui_state.last_click {
                                    prev_row == mouse.row && prev_time.elapsed().as_millis() < 400
                                } else {
                                    false
                                };
                            ui_state.last_click =
                                Some((mouse.column, mouse.row, std::time::Instant::now()));

                            if let Some(action) = click_regions.hit_test(mouse.column, mouse.row) {
                                match action.clone() {
                                    ui::ClickAction::SwitchTab(tab_idx) => {
                                        ui_state.selected_tab = tab_idx;
                                    }
                                    ui::ClickAction::SelectConnection(conn_idx) => {
                                        if ui_state.grouping_enabled {
                                            ui_state.set_selected_grouped_by_index(
                                                &grouped_rows,
                                                conn_idx,
                                            );
                                            if is_double_click
                                                && let Some(row) = grouped_rows.get(conn_idx)
                                            {
                                                match row {
                                                    ui::GroupedRow::Group { .. } => {
                                                        // Double-click group header: toggle expand/collapse
                                                        ui_state.toggle_group_expansion();
                                                        needs_regroup = true;
                                                    }
                                                    ui::GroupedRow::Connection { .. } => {
                                                        // Double-click connection: open Details tab
                                                        ui_state.selected_tab = 1;
                                                    }
                                                }
                                            }
                                        } else {
                                            ui_state.set_selected_by_index(&connections, conn_idx);
                                            if is_double_click {
                                                // Double-click connection in flat view: open Details tab
                                                ui_state.selected_tab = 1;
                                            }
                                        }
                                    }
                                    ui::ClickAction::CopyField { label, value } => {
                                        copy_to_clipboard(
                                            &value,
                                            &format!("{}: {}", label, value),
                                            &mut ui_state,
                                            app,
                                        );
                                    }
                                }
                            }
                        }
                        MouseEventKind::ScrollUp => {
                            if let Some(scroll_area) = click_regions.scroll_area
                                && mouse.column >= scroll_area.x
                                && mouse.column < scroll_area.x + scroll_area.width
                                && mouse.row >= scroll_area.y
                                && mouse.row < scroll_area.y + scroll_area.height
                                && ui_state.selected_tab == 0
                            {
                                if ui_state.grouping_enabled {
                                    ui_state.move_selection_up_grouped(&grouped_rows);
                                } else {
                                    ui_state.move_selection_up(&connections);
                                }
                            }
                        }
                        MouseEventKind::ScrollDown => {
                            if let Some(scroll_area) = click_regions.scroll_area
                                && mouse.column >= scroll_area.x
                                && mouse.column < scroll_area.x + scroll_area.width
                                && mouse.row >= scroll_area.y
                                && mouse.row < scroll_area.y + scroll_area.height
                                && ui_state.selected_tab == 0
                            {
                                if ui_state.grouping_enabled {
                                    ui_state.move_selection_down_grouped(&grouped_rows);
                                } else {
                                    ui_state.move_selection_down(&connections);
                                }
                            }
                        }
                        _ => {}
                    }
                }
                crossterm::event::Event::Key(key) => {
                    use crossterm::event::{KeyCode, KeyEventKind, KeyModifiers};

                    // On Windows, crossterm reports both Press and Release events
                    // On Linux/macOS, only Press events are reported
                    // Filter to only handle Press events for consistent cross-platform behavior
                    if key.kind != KeyEventKind::Press {
                        continue;
                    }

                    if ui_state.filter_mode {
                        // Handle input in filter mode
                        match key.code {
                            KeyCode::Enter => {
                                // Apply filter and exit input mode (now optional)
                                debug!("Exiting filter mode. Filter: '{}'", ui_state.filter_query);
                                ui_state.exit_filter_mode();
                                needs_data_refresh = true;
                                debug!("Filter mode now: {}", ui_state.filter_mode);
                            }
                            KeyCode::Esc => {
                                // Clear filter and exit filter mode
                                ui_state.clear_filter();
                                needs_data_refresh = true;
                            }
                            KeyCode::Backspace => {
                                ui_state.filter_backspace();
                                needs_data_refresh = true;
                            }
                            KeyCode::Delete
                                if ui_state.filter_cursor_position
                                    < ui_state.filter_query.len() =>
                            {
                                ui_state
                                    .filter_query
                                    .remove(ui_state.filter_cursor_position);
                                needs_data_refresh = true;
                            }
                            KeyCode::Left => {
                                ui_state.filter_cursor_left();
                            }
                            KeyCode::Right => {
                                ui_state.filter_cursor_right();
                            }
                            KeyCode::Home => {
                                ui_state.filter_cursor_position = 0;
                            }
                            KeyCode::End => {
                                ui_state.filter_cursor_position = ui_state.filter_query.len();
                            }
                            // Allow navigation while in filter mode!
                            KeyCode::Up => {
                                // Use the SAME sorted connections list from the main loop
                                // to ensure index consistency with the displayed table
                                debug!(
                                    "Filter mode navigation UP: {} connections available",
                                    connections.len()
                                );
                                ui_state.move_selection_up(&connections);
                            }
                            KeyCode::Down => {
                                // Use the SAME sorted connections list from the main loop
                                // to ensure index consistency with the displayed table
                                debug!(
                                    "Filter mode navigation DOWN: {} connections available",
                                    connections.len()
                                );
                                ui_state.move_selection_down(&connections);
                            }
                            KeyCode::Char(c) => {
                                // Handle Ctrl+H as backspace for SecureCRT compatibility
                                if c == 'h' && key.modifiers.contains(KeyModifiers::CONTROL) {
                                    ui_state.filter_backspace();
                                    return Ok(());
                                }

                                // All other characters (including j/k) are text input.
                                // Use arrow keys to navigate while typing.
                                ui_state.filter_add_char(c);
                                needs_data_refresh = true;
                            }
                            _ => {}
                        }
                    } else {
                        // Handle input in normal mode
                        match (key.code, key.modifiers) {
                            // Enter filter mode with '/' (only on Overview tab)
                            (KeyCode::Char('/'), _) if ui_state.selected_tab == 0 => {
                                ui_state.quit_confirmation = false;
                                debug!("Entering filter mode");
                                ui_state.enter_filter_mode();
                                debug!("Filter mode now: {}", ui_state.filter_mode);
                            }

                            // Quit with confirmation
                            (KeyCode::Char('q'), _) => {
                                if ui_state.quit_confirmation {
                                    info!("User confirmed application exit");
                                    break;
                                } else {
                                    info!("User requested quit - showing confirmation");
                                    ui_state.quit_confirmation = true;
                                }
                            }

                            // Ctrl+C always quits immediately
                            (KeyCode::Char('c'), KeyModifiers::CONTROL) => {
                                info!("User requested immediate exit with Ctrl+C");
                                break;
                            }

                            // Tab navigation (forward)
                            (KeyCode::Tab, KeyModifiers::NONE) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                ui_state.selected_tab = (ui_state.selected_tab + 1) % 5;
                            }

                            // Shift+Tab navigation (backward)
                            (KeyCode::BackTab, _) | (KeyCode::Tab, KeyModifiers::SHIFT) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                ui_state.selected_tab = if ui_state.selected_tab == 0 {
                                    4 // Wrap to last tab
                                } else {
                                    ui_state.selected_tab - 1
                                };
                            }

                            // Help toggle
                            (KeyCode::Char('h'), _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                ui_state.show_help = !ui_state.show_help;
                                if ui_state.show_help {
                                    ui_state.selected_tab = 4; // Switch to help tab
                                } else {
                                    ui_state.selected_tab = 0; // Back to overview
                                }
                            }

                            // Interface stats toggle (shortcut to Interface tab)
                            (KeyCode::Char('i'), _) | (KeyCode::Char('I'), _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                if ui_state.selected_tab == 2 {
                                    ui_state.selected_tab = 0; // Back to overview
                                } else {
                                    ui_state.selected_tab = 2; // Switch to interfaces tab
                                }
                            }

                            // Navigation in connection list
                            (KeyCode::Up, _) | (KeyCode::Char('k'), _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                if ui_state.grouping_enabled {
                                    debug!(
                                        "Navigation UP (grouped): {} rows available",
                                        grouped_rows.len()
                                    );
                                    ui_state.move_selection_up_grouped(&grouped_rows);
                                } else {
                                    debug!(
                                        "Navigation UP: {} connections available",
                                        connections.len()
                                    );
                                    ui_state.move_selection_up(&connections);
                                }
                            }

                            (KeyCode::Down, _) | (KeyCode::Char('j'), _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                if ui_state.grouping_enabled {
                                    debug!(
                                        "Navigation DOWN (grouped): {} rows available",
                                        grouped_rows.len()
                                    );
                                    ui_state.move_selection_down_grouped(&grouped_rows);
                                } else {
                                    debug!(
                                        "Navigation DOWN: {} connections available",
                                        connections.len()
                                    );
                                    ui_state.move_selection_down(&connections);
                                }
                            }

                            // Page Up/Down navigation
                            (KeyCode::PageUp, _) | (KeyCode::Char('b'), KeyModifiers::CONTROL) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                let page_size = ui_state.visible_rows.max(1);
                                if ui_state.grouping_enabled {
                                    ui_state
                                        .move_selection_page_up_grouped(&grouped_rows, page_size);
                                } else {
                                    ui_state.move_selection_page_up(&connections, page_size);
                                }
                            }

                            (KeyCode::PageDown, _)
                            | (KeyCode::Char('f'), KeyModifiers::CONTROL) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                let page_size = ui_state.visible_rows.max(1);
                                if ui_state.grouping_enabled {
                                    ui_state
                                        .move_selection_page_down_grouped(&grouped_rows, page_size);
                                } else {
                                    ui_state.move_selection_page_down(&connections, page_size);
                                }
                            }

                            // Vim-style jump to first/last (g/G)
                            (KeyCode::Char('g'), KeyModifiers::NONE) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                // Jump to first connection (vim-style 'g')
                                ui_state.move_selection_to_first(&connections);
                            }

                            (KeyCode::Char('G'), _) | (KeyCode::Char('g'), KeyModifiers::SHIFT) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                // Jump to last connection (vim-style 'G')
                                ui_state.move_selection_to_last(&connections);
                            }

                            // Enter to view details (only works on connections, not group headers)
                            (KeyCode::Enter, _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                if ui_state.selected_tab == 0
                                    && !connections.is_empty()
                                    && !(ui_state.grouping_enabled && ui_state.is_group_selected())
                                {
                                    // Switch to details view when on a connection (not a group header)
                                    ui_state.selected_tab = 1;
                                }
                            }

                            // Space to toggle group expansion
                            (KeyCode::Char(' '), _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                if ui_state.selected_tab == 0
                                    && ui_state.grouping_enabled
                                    && ui_state.is_group_selected()
                                {
                                    ui_state.toggle_group_expansion();
                                    needs_regroup = true;
                                }
                            }

                            // Left arrow to collapse group
                            (KeyCode::Left, _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                if ui_state.selected_tab == 0 && ui_state.grouping_enabled {
                                    ui_state.collapse_selected_group();
                                    needs_regroup = true;
                                }
                            }

                            // Right arrow to expand group
                            (KeyCode::Right, _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                if ui_state.selected_tab == 0 && ui_state.grouping_enabled {
                                    ui_state.expand_selected_group();
                                    needs_regroup = true;
                                }
                            }

                            // 'l' to expand group (vim-style, in addition to right arrow)
                            (KeyCode::Char('l'), _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                if ui_state.selected_tab == 0 && ui_state.grouping_enabled {
                                    ui_state.expand_selected_group();
                                    needs_regroup = true;
                                }
                            }

                            // 'a' to toggle grouping (aggregate) mode
                            (KeyCode::Char('a'), _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                ui_state.toggle_grouping();
                                needs_regroup = true;
                                info!(
                                    "Grouping mode: {}",
                                    if ui_state.grouping_enabled {
                                        "enabled (grouped by process)"
                                    } else {
                                        "disabled (flat list)"
                                    }
                                );
                            }

                            // 'r' to reset all view settings (grouping, sort, filter, historic)
                            (KeyCode::Char('r'), _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                let was_historic = ui_state.show_historic;
                                ui_state.reset_view();
                                if was_historic {
                                    app.set_show_historic(false);
                                }
                                needs_data_refresh = true;
                                info!("Reset view settings to defaults");
                            }

                            // Toggle port number display
                            (KeyCode::Char('p'), _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                ui_state.show_port_numbers = !ui_state.show_port_numbers;
                                info!(
                                    "Toggled port display: {}",
                                    if ui_state.show_port_numbers {
                                        "showing port numbers"
                                    } else {
                                        "showing service names"
                                    }
                                );
                            }

                            // Toggle hostname display (when DNS resolution is enabled)
                            (KeyCode::Char('d'), _) => {
                                if app.is_dns_resolution_enabled() {
                                    ui_state.quit_confirmation = false;
                                    ui_state.clear_confirmation = false;
                                    ui_state.show_hostnames = !ui_state.show_hostnames;
                                    info!(
                                        "Toggled hostname display: {}",
                                        if ui_state.show_hostnames {
                                            "showing hostnames"
                                        } else {
                                            "showing IP addresses"
                                        }
                                    );
                                }
                            }

                            // Toggle historic connections display
                            (KeyCode::Char('t'), _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                ui_state.show_historic = !ui_state.show_historic;
                                ui_state.scroll_offset = 0;
                                ui_state.grouped_scroll_offset = 0;
                                app.toggle_show_historic();
                                needs_data_refresh = true;
                                info!(
                                    "Historic connections: {}",
                                    if ui_state.show_historic {
                                        "showing"
                                    } else {
                                        "hidden"
                                    }
                                );
                            }

                            // Cycle sort column with 's'
                            (KeyCode::Char('s'), KeyModifiers::NONE) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                ui_state.cycle_sort_column();
                                needs_data_refresh = true;
                                info!(
                                    "Sort column: {} ({})",
                                    ui_state.sort_column.display_name(),
                                    if ui_state.sort_ascending {
                                        "ascending"
                                    } else {
                                        "descending"
                                    }
                                );
                            }

                            // Toggle sort direction with 'S' (Shift+s)
                            (KeyCode::Char('S'), _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                ui_state.toggle_sort_direction();
                                needs_data_refresh = true;
                                info!(
                                    "Sort direction: {} ({})",
                                    if ui_state.sort_ascending {
                                        "ascending"
                                    } else {
                                        "descending"
                                    },
                                    ui_state.sort_column.display_name()
                                );
                            }

                            // Copy remote address to clipboard
                            (KeyCode::Char('c'), _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                if let Some(selected_idx) =
                                    ui_state.get_selected_index(&connections)
                                    && let Some(conn) = connections.get(selected_idx)
                                {
                                    let remote_addr = conn.remote_addr.to_string();
                                    copy_to_clipboard(
                                        &remote_addr,
                                        &remote_addr,
                                        &mut ui_state,
                                        app,
                                    );
                                }
                            }

                            // Clear all connections with confirmation
                            (KeyCode::Char('x'), _) => {
                                ui_state.quit_confirmation = false;
                                if ui_state.clear_confirmation {
                                    info!("User confirmed clear all connections");
                                    app.clear_all_connections();
                                    ui_state.clear_confirmation = false;
                                    ui_state.show_historic = false;
                                    ui_state.selected_connection_key = None;
                                    ui_state.clipboard_message = Some((
                                        "All connections cleared".to_string(),
                                        std::time::Instant::now(),
                                    ));
                                    needs_data_refresh = true;
                                } else {
                                    info!("User requested clear - showing confirmation");
                                    ui_state.clear_confirmation = true;
                                }
                            }

                            // Escape to go back or clear filter
                            (KeyCode::Esc, _) => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                                if !ui_state.filter_query.is_empty() {
                                    // Clear filter if one is active
                                    ui_state.clear_filter();
                                    needs_data_refresh = true;
                                } else if ui_state.selected_tab != 0 {
                                    // Back to overview from any other tab
                                    ui_state.selected_tab = 0;
                                }
                            }

                            // Any other key resets confirmations
                            _ => {
                                ui_state.quit_confirmation = false;
                                ui_state.clear_confirmation = false;
                            }
                        }
                    }
                } // end Event::Key
                _ => {} // ignore resize, focus, paste, etc.
            } // end match event
        } // end if poll
    } // end loop

    Ok(())
}

/// Check if we have privileges for packet capture before starting the TUI
fn check_privileges_early() -> Result<()> {
    match network::privileges::check_packet_capture_privileges() {
        Ok(status) if !status.has_privileges => {
            // Print error to stderr before TUI starts
            eprintln!(
                "\n╔═══════════════════════════════════════════════════════════════════════════╗"
            );
            eprintln!(
                "║                   INSUFFICIENT PRIVILEGES                                 ║"
            );
            eprintln!(
                "╚═══════════════════════════════════════════════════════════════════════════╝"
            );
            eprintln!();
            eprintln!("{}", status.error_message());

            return Err(anyhow::anyhow!(
                "Insufficient privileges for packet capture"
            ));
        }
        Err(e) => {
            // Privilege check failed - warn but continue
            eprintln!("Warning: Failed to check privileges: {}", e);
            eprintln!("Continuing anyway, but packet capture may fail...\n");
        }
        _ => {
            // Privileges OK
        }
    }

    Ok(())
}

#[cfg(target_os = "windows")]
fn check_windows_dependencies() -> Result<()> {
    use anyhow::anyhow;

    // Check if Npcap/WinPcap DLLs are available
    // Try to load the DLLs to see if they're in the system path
    let wpcap_available = check_dll_available("wpcap.dll");
    let packet_available = check_dll_available("Packet.dll");

    if !wpcap_available || !packet_available {
        eprintln!(
            "\n╔═══════════════════════════════════════════════════════════════════════════╗"
        );
        eprintln!("║                          MISSING DEPENDENCY                               ║");
        eprintln!("╚═══════════════════════════════════════════════════════════════════════════╝");
        eprintln!();
        eprintln!("RustNet requires Npcap for packet capture on Windows.");
        eprintln!();

        if !wpcap_available {
            eprintln!("  ✗ wpcap.dll not found");
        }
        if !packet_available {
            eprintln!("  ✗ Packet.dll not found");
        }

        eprintln!();
        eprintln!("To fix this:");
        eprintln!();
        eprintln!("  1. Download Npcap from: https://npcap.com/dist/");
        eprintln!("  2. Run the installer");
        eprintln!("  3. IMPORTANT: Check \"Install Npcap in WinPcap API-compatible Mode\"");
        eprintln!("  4. Complete the installation");
        eprintln!();
        eprintln!("After installation, restart your terminal and try again.");
        eprintln!();

        return Err(anyhow!(
            "Npcap is not installed or not in WinPcap compatible mode"
        ));
    }

    Ok(())
}

#[cfg(target_os = "windows")]
fn check_dll_available(dll_name: &str) -> bool {
    use std::ffi::CString;
    use windows::Win32::Foundation::{FreeLibrary, HMODULE};
    use windows::Win32::System::LibraryLoader::LoadLibraryA;
    use windows::core::PCSTR;

    // Try to load the DLL
    let dll_cstring = match CString::new(dll_name) {
        Ok(s) => s,
        Err(_) => return false,
    };

    unsafe {
        // Use LoadLibraryA to check if the DLL can be loaded
        let handle = LoadLibraryA(PCSTR(dll_cstring.as_ptr() as *const u8));

        if let Ok(h) = handle
            && h != HMODULE(std::ptr::null_mut())
        {
            // Free the library if it was loaded
            let _ = FreeLibrary(h);
            true
        } else {
            false
        }
    }
}

/// Check if the current process is running with Administrator privileges (Windows only)
#[cfg(target_os = "windows")]
fn is_admin() -> bool {
    use windows::Win32::Foundation::HANDLE;
    use windows::Win32::Security::{
        GetTokenInformation, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation,
    };
    use windows::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken};

    unsafe {
        let mut token_handle = HANDLE::default();

        // Open the process token
        if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token_handle).is_err() {
            return false;
        }

        let mut elevation = TOKEN_ELEVATION::default();
        let mut return_length = 0u32;

        // Get the elevation information
        let result = GetTokenInformation(
            token_handle,
            TokenElevation,
            Some(&mut elevation as *mut _ as *mut _),
            std::mem::size_of::<TOKEN_ELEVATION>() as u32,
            &mut return_length,
        );

        // Close the token handle
        let _ = windows::Win32::Foundation::CloseHandle(token_handle);

        if result.is_err() {
            return false;
        }

        elevation.TokenIsElevated != 0
    }
}
