use std::{io::stdout, path::PathBuf, time::Duration};

use anyhow::{Context, Result};
use clap::Parser;
use crossterm::{
    event::{self, Event, KeyEventKind},
    event::{DisableMouseCapture, EnableMouseCapture},
    execute,
    terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
};
use ratatui::{Terminal, backend::CrosstermBackend};
use rogue_agenda::{App, Database, Preset, ui};

#[derive(Debug, Parser)]
#[command(
    name = "rogue-agenda",
    version,
    about = "A category-driven personal information manager for the terminal"
)]
struct Args {
    /// Rogue Agenda SQLite document (the .agnd extension is added if absent)
    #[arg(default_value = "rogue.agnd")]
    document: PathBuf,
    /// Populate a new document with representative items
    #[arg(long)]
    demo: bool,
    /// Initialize a new document with a complete example workspace
    #[arg(long, value_enum, conflicts_with = "demo")]
    preset: Option<Preset>,
    /// Import a text or iCalendar (.ics) file, then exit
    #[arg(long)]
    import: Option<PathBuf>,
    /// Export as csv, json, markdown, html, or ics, then exit
    #[arg(long, value_name = "FORMAT")]
    export: Option<String>,
    /// Destination for --export
    #[arg(long)]
    output: Option<PathBuf>,
    /// Saved view to use for export (defaults to All Items)
    #[arg(long, requires = "export")]
    view: Option<String>,
}

fn main() -> Result<()> {
    let args = Args::parse();
    let mut path = args.document;
    if path.extension().is_none() {
        path.set_extension("agnd");
    }
    let mut db = Database::open(&path)?;
    if args.demo {
        db.seed_demo()?;
    }
    if let Some(preset) = args.preset {
        db.apply_preset(preset)?;
    }
    if let Some(import) = args.import {
        let count = db.import_path(&import)?;
        println!("Imported {count} item(s) into {}", path.display());
        return Ok(());
    }
    if let Some(format) = args.export {
        let output = args.output.context("--output is required with --export")?;
        let count = db.export(&format, &output, args.view.as_deref())?;
        println!("Exported {count} item(s) to {}", output.display());
        return Ok(());
    }
    run_tui(App::new(db, path)?)
}

fn run_tui(mut app: App) -> Result<()> {
    enable_raw_mode()?;
    let _guard = TerminalGuard;
    let mut out = stdout();
    execute!(out, EnterAlternateScreen, EnableMouseCapture)?;
    let backend = CrosstermBackend::new(out);
    let mut terminal = Terminal::new(backend)?;
    terminal.clear()?;
    let result = (|| -> Result<()> {
        loop {
            app.tick()?;
            terminal.draw(|f| ui::draw(f, &mut app))?;
            if app.should_quit() {
                break;
            }
            if event::poll(Duration::from_millis(250))? {
                match event::read()? {
                    Event::Key(k) if k.kind == KeyEventKind::Press => app.handle_key(k)?,
                    Event::Mouse(m) => app.handle_mouse(m)?,
                    Event::Resize(_, _) => {}
                    _ => {}
                }
            }
        }
        app.shutdown()?;
        Ok(())
    })();
    terminal.show_cursor()?;
    if let Err(e) = result {
        return Err(e.context("Rogue Agenda session ended unexpectedly"));
    }
    Ok(())
}

struct TerminalGuard;

impl Drop for TerminalGuard {
    fn drop(&mut self) {
        let _ = disable_raw_mode();
        let _ = execute!(stdout(), DisableMouseCapture, LeaveAlternateScreen);
    }
}
