//! Scanner view — find leaked secrets in files.
//!
//! Note: The scan functionality is invoked via the CLI subprocess since
//! the scanner requires filesystem traversal. The GUI provides config
//! and displays results.

use std::path::PathBuf;

use eframe::egui;

/// Prefer the CLI next to this binary (same install dir) over `PATH` hijacking.
fn resolve_envseal_cli() -> PathBuf {
    if let Ok(exe) = std::env::current_exe() {
        if let Some(dir) = exe.parent() {
            let mut candidate = dir.join("envseal");
            #[cfg(windows)]
            {
                candidate.set_extension("exe");
            }
            if candidate.is_file() {
                return candidate;
            }
        }
    }
    PathBuf::from("envseal")
}

#[derive(Default)]
pub struct ScannerState {
    pub scan_path: String,
    pub deep: bool,
    pub result_text: Option<String>,
    pub clean: Option<bool>,
}

pub fn render(ui: &mut egui::Ui, state: &mut ScannerState) {
    ui.add_space(8.0);
    ui.horizontal(|ui| {
        ui.heading("Secret Scanner");
        ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
            let btn = ui.add(
                egui::Button::new("🔍 Run Scan")
                    .fill(egui::Color32::from_rgb(0xe4, 0xe4, 0xe7))
                    .min_size(egui::vec2(100.0, 30.0))
                    .corner_radius(8.0),
            );
            if btn.clicked() {
                // Run scan command and capture output.
                let mut cmd = std::process::Command::new(resolve_envseal_cli());
                cmd.arg("scan");
                if !state.scan_path.is_empty() {
                    cmd.arg("--path").arg(&state.scan_path);
                }
                if state.deep {
                    cmd.arg("--deep");
                }
                match cmd.output() {
                    Ok(output) => {
                        let out = String::from_utf8_lossy(&output.stdout).to_string();
                        let err = String::from_utf8_lossy(&output.stderr).to_string();
                        let combined = if err.is_empty() {
                            out
                        } else {
                            format!("{out}\n{err}")
                        };
                        // The CLI prints "Clean  No leaks found" on a
                        // green badge when nothing is found, and
                        // "Leaks  N potential leak(s)" on a red badge
                        // otherwise. Match against those exact phrases —
                        // the older heuristics ("no leaked" / "0 findings")
                        // never appear in the current output and would
                        // always fall through to the red panel.
                        state.clean = Some(
                            combined.contains("No leaks found")
                                && !combined.contains("potential leak"),
                        );
                        state.result_text = Some(combined);
                    }
                    Err(e) => {
                        state.result_text = Some(format!("Failed to run scan: {e}"));
                        state.clean = Some(false);
                    }
                }
            }
        });
    });
    ui.add_space(4.0);
    ui.label(
        egui::RichText::new("Scan files for leaked API keys, tokens, and credentials.").weak(),
    );
    ui.add_space(12.0);

    // Config.
    egui::Frame::new()
        .fill(ui.visuals().faint_bg_color)
        .corner_radius(8.0)
        .inner_margin(12.0)
        .show(ui, |ui| {
            ui.label(egui::RichText::new("Scan Target").strong());
            ui.add(
                egui::TextEdit::singleline(&mut state.scan_path)
                    .hint_text("Leave empty for shell configs, or enter a path...")
                    .desired_width(f32::INFINITY),
            );
            ui.checkbox(&mut state.deep, "Deep scan (entire $HOME + git history)");
        });

    ui.add_space(12.0);

    // Results.
    match (&state.result_text, state.clean) {
        (None, _) => {
            ui.add_space(30.0);
            ui.vertical_centered(|ui| {
                ui.label(egui::RichText::new("🔍").size(36.0));
                ui.label("No scan results yet");
                ui.label(egui::RichText::new("Click \"Run Scan\" to find leaked secrets").weak());
            });
        }
        (Some(text), Some(true)) => {
            egui::Frame::new()
                .fill(egui::Color32::from_rgba_premultiplied(6, 78, 59, 40))
                .corner_radius(8.0)
                .inner_margin(16.0)
                .show(ui, |ui| {
                    ui.label(
                        egui::RichText::new("✅ No leaked secrets found")
                            .color(egui::Color32::from_rgb(0x22, 0xc5, 0x5e))
                            .size(15.0),
                    );
                });
            ui.add_space(8.0);
            ui.label(egui::RichText::new(text).size(12.0).weak());
        }
        (Some(text), _) => {
            egui::Frame::new()
                .fill(egui::Color32::from_rgba_premultiplied(127, 29, 29, 40))
                .corner_radius(8.0)
                .inner_margin(12.0)
                .show(ui, |ui| {
                    ui.label(
                        egui::RichText::new("⚠ Potential findings detected")
                            .color(egui::Color32::from_rgb(239, 68, 68))
                            .size(15.0),
                    );
                });
            ui.add_space(8.0);
            egui::ScrollArea::vertical().show(ui, |ui| {
                ui.label(egui::RichText::new(text).size(12.0));
            });
        }
    }
}
