use crossterm::{
    ExecutableCommand,
    event::{self, Event, KeyCode, KeyEventKind},
    terminal::{EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode},
};
use ratatui::{Terminal, backend::CrosstermBackend};
use std::io::stdout;
use std::path::PathBuf;

use crate::core::Result;
use crate::core::store::Store;

use super::screens::auth::{self, AuthScreen};
use super::screens::init::{self, InitScreen};
use super::screens::list::{self, ListScreen};

/// The active TUI screen variant.
pub enum Screen {
    /// Vault initialization screen.
    Init(InitScreen),
    /// Password authentication screen.
    Auth(AuthScreen),
    /// Provider list and selection screen.
    List(ListScreen),
}

/// The main TUI application state.
pub struct App {
    /// The currently active screen.
    pub screen: Screen,
    /// Whether the application should exit the event loop.
    pub should_quit: bool,
    /// The encrypted vault store backend.
    pub store: Store,
}

impl App {
    /// Creates a new App, routing to the appropriate starting screen based on vault state.
    pub fn new(store: Store) -> Result<Self> {
        let screen = if store.is_authenticated() {
            Screen::List(ListScreen::load(&store)?)
        } else if store.has_encrypted() {
            Screen::Auth(AuthScreen::new())
        } else {
            Screen::Init(InitScreen::new())
        };
        Ok(Self {
            screen,
            should_quit: false,
            store,
        })
    }
}

/// Enters the TUI, initializes the terminal, and runs the event loop.
pub fn run() -> Result<()> {
    enable_raw_mode()?;
    stdout().execute(EnterAlternateScreen)?;
    let backend = CrosstermBackend::new(stdout());
    let mut terminal = Terminal::new(backend)?;

    let closure_dir = dirs::home_dir()
        .unwrap_or_else(|| PathBuf::from("."))
        .join(".kozbox")
        .join("closure")
        .join("workdata");
    std::fs::create_dir_all(&closure_dir)?;
    let store = Store::new(&closure_dir);

    let mut app = App::new(store)?;
    let result = run_app(&mut terminal, &mut app);

    disable_raw_mode()?;
    stdout().execute(LeaveAlternateScreen)?;

    result
}

fn run_app<B: ratatui::backend::Backend>(terminal: &mut Terminal<B>, app: &mut App) -> Result<()> {
    let mut filter_mode = false;

    while !app.should_quit {
        terminal.draw(|frame| match &mut app.screen {
            Screen::Init(screen) => {
                init::draw(frame, screen);
            }
            Screen::Auth(screen) => {
                auth::draw(frame, screen);
            }
            Screen::List(screen) => {
                list::draw(frame, screen);
            }
        })?;

        if let Event::Key(key) = event::read()? {
            if key.kind == KeyEventKind::Press {
                match &mut app.screen {
                    Screen::Init(screen) => match key.code {
                        KeyCode::Char(c) => match screen.handle_input(c, &app.store)? {
                            Some(true) => {
                                // Init complete → go to auth
                                app.screen = Screen::Auth(AuthScreen::new());
                            }
                            Some(false) => {
                                // User declined → quit
                                app.should_quit = true;
                            }
                            None => {}
                        },
                        KeyCode::Backspace => screen.handle_backspace(),
                        KeyCode::Esc => app.should_quit = true,
                        _ => {}
                    },
                    Screen::Auth(screen) => match key.code {
                        KeyCode::Char(c) => {
                            if screen.handle_input(c, &app.store)? {
                                app.screen = Screen::List(ListScreen::load(&app.store)?);
                            }
                        }
                        KeyCode::Backspace => screen.handle_backspace(),
                        KeyCode::Esc => app.should_quit = true,
                        _ => {}
                    },
                    Screen::List(screen) => {
                        if let Some(true) =
                            list::handle_event(screen, key.code, &mut filter_mode, &app.store)
                        {
                            app.should_quit = true;
                        }
                    }
                }
            }
        }
    }
    Ok(())
}
