use std::{fs::File, io::stdout, path::Path};

use anyhow::Result;
use crossterm::{
    event::{DisableMouseCapture, EnableMouseCapture},
    execute,
    terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
};
use log::{error, info, warn};
use ratatui::{Terminal, backend::CrosstermBackend};
use simplelog::{LevelFilter, WriteLogger};

// Use modules from the library crate
#[cfg(not(feature = "pdf"))]
use bookokrat::event_source::KeyboardEventSource;
#[cfg(feature = "pdf")]
use bookokrat::inputs::UnifiedEventSource;
use bookokrat::library;
use bookokrat::main_app::{App, run_app_with_event_source};
#[cfg(feature = "pdf")]
use bookokrat::main_app::{
    set_kitty_delete_range_support_override, set_kitty_shm_support_override,
};
use bookokrat::panic_handler;
#[cfg(feature = "pdf")]
use bookokrat::pdf::kittyv2::{delete_all_images, kgfx::cleanup_all_shms};
use bookokrat::settings;
#[cfg(feature = "pdf")]
use bookokrat::terminal;
use bookokrat::theme::load_custom_themes;

struct CliArgs {
    file_path: Option<String>,
    zen_mode: bool,
    test_mode: bool,
}

fn parse_args() -> Result<CliArgs> {
    let mut file_path = None;
    let mut zen_mode = false;
    let mut test_mode = false;

    for arg in std::env::args().skip(1) {
        match arg.as_str() {
            "--zen-mode" => zen_mode = true,
            "--test-mode" => test_mode = true,
            "--help" | "-h" => {
                println!("Usage: bookokrat [FILE.epub] [--zen-mode] [--test-mode]");
                std::process::exit(0);
            }
            "--version" | "-V" => {
                println!("bookokrat {}", env!("CARGO_PKG_VERSION"));
                std::process::exit(0);
            }
            _ if arg.starts_with('-') => {
                anyhow::bail!("Unknown option: {arg}");
            }
            _ => {
                if file_path.is_some() {
                    anyhow::bail!("Only one file path can be provided.");
                }
                file_path = Some(arg);
            }
        }
    }

    Ok(CliArgs {
        file_path,
        zen_mode,
        test_mode,
    })
}

fn main() -> Result<()> {
    // Initialize panic handler first, before any other setup
    panic_handler::initialize_panic_handler();

    let args = parse_args()?;

    // Resolve library directory from file argument or CWD
    let library_dir = args
        .file_path
        .as_deref()
        .and_then(|p| Path::new(p).parent())
        .filter(|p| !p.as_os_str().is_empty())
        .map(|p| p.to_path_buf())
        .unwrap_or_else(|| std::env::current_dir().unwrap_or_default());

    let lib_paths = library::resolve_library_paths(&library_dir);
    let log_path = library::resolve_log_path();

    // Run migration before logging is initialized (prints to stdout)
    if !args.test_mode {
        if let Ok(ref paths) = lib_paths {
            if let Err(e) = library::migrate_if_needed(&library_dir, paths) {
                eprintln!("Warning: migration failed: {e}");
            }
        }
    }

    // Initialize logging with html5ever DEBUG logs filtered out
    let log_file = match log_path {
        Ok(ref p) => File::create(p)?,
        Err(_) => File::create("bookokrat.log")?,
    };
    WriteLogger::init(
        LevelFilter::Debug,
        simplelog::ConfigBuilder::new()
            .set_max_level(LevelFilter::Debug)
            .add_filter_ignore_str("html5ever")
            .build(),
        log_file,
    )?;

    if let Err(ref e) = lib_paths {
        warn!("Failed to resolve XDG library paths, falling back to CWD: {e}");
    }

    // Validate file argument before entering TUI
    if let Some(ref path) = args.file_path {
        if !Path::new(path).exists() {
            eprintln!("Error: file not found: {path}");
            std::process::exit(1);
        }
        if bookokrat::book_manager::BookManager::detect_format(path).is_none() {
            eprintln!("Error: unsupported file format: {path}");
            std::process::exit(1);
        }
    }

    info!("Starting Bookokrat EPUB reader");

    #[cfg(feature = "pdf")]
    {
        let caps = terminal::detect_terminal();
        info!(
            "Startup terminal caps: kind={:?}, tmux={}, truecolor={}, graphics={}, \
             protocol={:?}, pdf_supported={}, pdf_scroll_mode={}, pdf_comments={}, \
             TERM_PROGRAM={:?}, TERM={:?}, kitty_window={}, kitty_pid={}, wezterm_executable={}",
            caps.kind,
            caps.env.tmux,
            caps.supports_true_color,
            caps.supports_graphics,
            caps.protocol,
            caps.pdf.supported,
            caps.pdf.supports_scroll_mode,
            caps.pdf.supports_comments,
            caps.env.term_program,
            caps.env.term,
            caps.env.kitty_window,
            caps.env.kitty_pid,
            caps.env.wezterm_executable,
        );
        if caps.env.tmux {
            bookokrat::pdf::kittyv2::set_tmux(true);
            terminal::enable_tmux_passthrough();
        }
        set_kitty_shm_support_override(terminal::probe_kitty_shm_support(&caps));
        set_kitty_delete_range_support_override(terminal::probe_kitty_delete_range_support(&caps));
    }
    // Terminal initialization
    enable_raw_mode()?;
    let mut stdout = stdout();

    execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    // Load settings (skip in test mode for reproducible state)
    if !args.test_mode {
        settings::load_settings();
        load_custom_themes();
    }

    // Create app and run it
    let book_directory = args
        .file_path
        .as_deref()
        .and_then(|path| Path::new(path).parent())
        .and_then(|parent| {
            if parent.as_os_str().is_empty() {
                None
            } else {
                parent.to_str()
            }
        });
    // In test mode: no auto-load, ephemeral bookmarks
    let auto_load_recent = args.file_path.is_none() && !args.test_mode;
    let (bookmark_file, comments_dir) = if args.test_mode {
        (None, None)
    } else if let Ok(ref paths) = lib_paths {
        (
            Some(paths.bookmarks_file.to_string_lossy().into_owned()),
            Some(paths.comments_dir.clone()),
        )
    } else {
        (Some("bookmarks.json".to_string()), None)
    };
    // Show loading indicator so the user knows the app isn't stuck
    // (Calibre library scans can take a few seconds)
    terminal.draw(|frame| {
        let area = frame.area();
        let y = area.height / 2;
        let centered = ratatui::layout::Rect::new(0, y, area.width, 1);
        frame.render_widget(
            ratatui::widgets::Paragraph::new("Scanning library...")
                .alignment(ratatui::layout::Alignment::Center)
                .style(ratatui::style::Style::default().fg(ratatui::style::Color::DarkGray)),
            centered,
        );
    })?;

    let image_cache_dir = lib_paths.as_ref().ok().map(|p| p.image_cache_dir.clone());
    let mut app = App::new_with_config(
        book_directory,
        bookmark_file.as_deref(),
        auto_load_recent,
        comments_dir.as_deref(),
        image_cache_dir,
    );
    app.set_zen_mode(args.zen_mode);
    app.set_test_mode(args.test_mode);
    if let Some(path) = args.file_path.as_deref() {
        if let Err(err) = app.open_book_for_reading_by_path(path) {
            error!("Failed to open requested book: {err}");
            panic_handler::restore_terminal();
            eprintln!("Error: failed to open {path}: {err}");
            std::process::exit(1);
        }
    }
    #[cfg(feature = "pdf")]
    let mut event_source = UnifiedEventSource::new();
    #[cfg(not(feature = "pdf"))]
    let mut event_source = KeyboardEventSource;
    let res = run_app_with_event_source(&mut terminal, &mut app, &mut event_source);

    // Delete all Kitty graphics images before leaving alternate screen
    #[cfg(feature = "pdf")]
    let _ = delete_all_images();

    // Restore terminal state
    disable_raw_mode()?;
    execute!(
        terminal.backend_mut(),
        LeaveAlternateScreen,
        DisableMouseCapture
    )?;
    terminal.show_cursor()?;

    if let Err(err) = res {
        error!("Application error: {err:?}");
        println!("{err:?}");
    }

    // Cleanup any remaining SHM objects
    #[cfg(feature = "pdf")]
    cleanup_all_shms();

    info!("Shutting down Bookokrat");
    Ok(())
}
