use anyhow::Result;
use crossterm::event::{Event, EventStream, KeyCode, KeyModifiers};
use futures::StreamExt;
use ratatui::DefaultTerminal;
use sqlx::sqlite::SqlitePool;
use tokio::sync::mpsc;
use tokio::time::{interval, Duration};
use tracing_appender::non_blocking::WorkerGuard;
use tracing_subscriber::EnvFilter;

use sba_scout::app::{App, AppMessage};
use sba_scout::config;
use sba_scout::db;

fn init_logging(log_dir: &std::path::Path) -> WorkerGuard {
    std::fs::create_dir_all(log_dir).ok();
    let file_appender = tracing_appender::rolling::never(log_dir, "sba-scout.log");
    let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
    tracing_subscriber::fmt()
        .with_writer(non_blocking)
        .with_env_filter(
            EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
        )
        .with_ansi(false)
        .init();
    guard
}

#[tokio::main]
async fn main() -> Result<()> {
    let settings = match config::load_settings() {
        Ok(s) => s,
        Err(e) => {
            eprintln!("Failed to load settings: {}", e);
            std::process::exit(1);
        }
    };

    let log_dir = settings.db_path.parent().unwrap_or(std::path::Path::new("data"));
    let _log_guard = init_logging(log_dir);

    if let Some(parent) = settings.db_path.parent() {
        std::fs::create_dir_all(parent)?;
    }

    let pool = db::schema::init_pool(&settings.db_path).await?;
    db::schema::create_tables(&pool).await?;

    let mut terminal = ratatui::init();
    let result = run(&mut terminal, settings, pool).await;
    ratatui::restore();
    result
}

async fn run(terminal: &mut DefaultTerminal, settings: config::Settings, pool: SqlitePool) -> Result<()> {
    let (tx, mut rx) = mpsc::unbounded_channel::<AppMessage>();
    let mut app = App::new(settings, pool, tx);

    app.on_mount();

    let mut event_stream = EventStream::new();
    let mut tick = interval(Duration::from_millis(250));

    loop {
        terminal.draw(|frame| app.render(frame))?;

        tokio::select! {
            maybe_event = event_stream.next() => {
                match maybe_event {
                    Some(Ok(Event::Key(key))) => {
                        if key.code == KeyCode::Char('q')
                            && key.modifiers == KeyModifiers::NONE
                            && app.should_quit_on_q()
                        {
                            break;
                        }
                        app.handle_key(key);
                    }
                    Some(Ok(Event::Resize(_, _))) => {
                        // ratatui handles resize on next draw
                    }
                    Some(Err(_)) => {}
                    None => break,
                    _ => {}
                }
            }

            maybe_msg = rx.recv() => {
                if let Some(msg) = maybe_msg {
                    app.handle_message(msg);
                }
            }

            _ = tick.tick() => {
                app.on_tick();
            }
        }
    }

    Ok(())
}
