//! File-based debug logger for Setup Portal.
//! When SETUP_PORTAL_DEBUG=1 or SETUP_PORTAL_DEBUG_FILE is set, all inputs and render state
//! are written to a file so you can capture the full trace when reproducing the navigation bug.
//!
//! Usage:
//!   set SETUP_PORTAL_DEBUG_FILE=setup-portal-debug.log
//!   mk3-tui   (or 4r)
//! Then open Setup Portal (windowed), reproduce the bug, exit. Inspect setup-portal-debug.log.

use std::io::Write;
use std::sync::Mutex;
use std::sync::OnceLock;
use std::time::{SystemTime, UNIX_EPOCH};

fn enabled() -> bool {
    std::env::var("SETUP_PORTAL_DEBUG").as_deref() == Ok("1")
        || std::env::var("SETUP_PORTAL_DEBUG_FILE").is_ok()
}

fn path() -> String {
    std::env::var("SETUP_PORTAL_DEBUG_FILE")
        .unwrap_or_else(|_| "setup-portal-debug.log".to_string())
}

static FILE: OnceLock<Mutex<Option<std::io::BufWriter<std::fs::File>>>> = OnceLock::new();

fn ensure_open() -> bool {
    if !enabled() {
        return false;
    }
    let mutex = FILE.get_or_init(|| Mutex::new(None));
    let mut guard = mutex.lock().unwrap();
    if guard.is_none() {
        let path = path();
        match std::fs::OpenOptions::new()
            .create(true)
            .append(true)
            .open(&path)
        {
            Ok(file_handle) => {
                // Resolve full path so user always knows where the log is
                let full_path: String = std::path::Path::new(&path)
                    .canonicalize()
                    .map(|p| p.display().to_string())
                    .or_else(|_| {
                        std::env::current_dir().map(|cwd| cwd.join(&path).display().to_string())
                    })
                    .unwrap_or_else(|_| path.clone());
                let _ = writeln!(
                    std::io::stderr(),
                    "[SETUP_PORTAL_DEBUG] Log file: {}",
                    full_path
                );
                let mut w = std::io::BufWriter::new(file_handle);
                let banner = format!(
                    "{} === Setup Portal debug log opened: {} ===\n",
                    timestamp(),
                    full_path
                );
                let _ = w.write_all(banner.as_bytes());
                let _ = w.flush();
                *guard = Some(w);
                return true;
            }
            Err(e) => {
                let _ = writeln!(
                    std::io::stderr(),
                    "[SETUP_PORTAL_DEBUG] Failed to open \"{}\": {}",
                    path,
                    e
                );
                return false;
            }
        }
    }
    true
}

fn log_raw(msg: &str) {
    if !enabled() {
        return;
    }
    if !ensure_open() {
        return;
    }
    let mutex = FILE.get().unwrap();
    let mut guard = mutex.lock().unwrap();
    if let Some(ref mut w) = *guard {
        let _ = w.write_all(msg.as_bytes());
        let _ = w.write_all(b"\n");
        let _ = w.flush();
    }
}

fn timestamp() -> String {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map(|d| format!("{}.{:03}", d.as_secs(), d.subsec_millis()))
        .unwrap_or_else(|_| "?.???".to_string())
}

/// Log a line with timestamp. Call from main or setup_portal when debug file is enabled.
pub fn log(msg: &str) {
    log_raw(&format!("{} {}", timestamp(), msg));
}

/// Log screen switch (enter/leave Setup Portal).
pub fn log_screen(from: &str, to: &str) {
    log(&format!("SCREEN {} -> {}", from, to));
}

/// Log an input event (key, mouse, resize).
pub fn log_input(kind: &str, detail: &str) {
    log(&format!("INPUT {} {}", kind, detail));
}

/// Log render state (dims, rects, selected option). Throttled by caller.
pub fn log_render(msg: &str) {
    log(&format!("RENDER {}", msg));
}

/// Log flicker-debug: when we clear and when we finish draw (to correlate with visible flicker).
/// Writes to debug file when SETUP_PORTAL_DEBUG or SETUP_PORTAL_DEBUG_FILE is set.
pub fn log_flicker_debug(event: &str, detail: &str) {
    let msg = format!("FLICKER {} {}", event, detail);
    log(&msg);
    // Also to stderr when file debug enabled, so "4r 2> setup-debug.log" captures it
    if enabled() {
        let _ = writeln!(std::io::stderr(), "[SETUP_PORTAL_DEBUG] {}", msg);
    }
}
