//! P1: bounded scripted event feed — same handling path as `run_loop` → `handle_event` (no real TTY).

use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
use serial_test::serial;
use tsafe_tui::app::{App, Screen, Theme};
use tsafe_tui::feed_events;

fn key(code: KeyCode, mods: KeyModifiers) -> Event {
    Event::Key(KeyEvent::new(code, mods))
}

fn app_dashboard_demo_empty(mut app: App) -> App {
    app.update_rx = None;
    app.update_available = None;
    app.profiles = vec!["demo".to_string()];
    app.profile_cursor = 0;
    app.active_profile = Some("demo".to_string());
    app.screen = Screen::Dashboard;
    app.secret_keys = vec![];
    app.secret_cursor = 0;
    app.search_mode = false;
    app.search_query.clear();
    app.theme = Theme::Dark;
    app
}

#[serial]
#[test]
fn feed_events_ctrl_c_requests_quit_on_login() {
    let dir = tempfile::tempdir().expect("tempdir");
    temp_env::with_var("TSAFE_VAULT_DIR", Some(dir.path().as_os_str()), || {
        let mut app = App::new();
        app.update_rx = None;
        app.update_available = None;
        let mut pw = None;
        let quit = feed_events(
            &mut app,
            [key(KeyCode::Char('c'), KeyModifiers::CONTROL)],
            &mut pw,
        );
        assert!(quit);
        assert_eq!(app.screen, Screen::Login);
    });
}

#[serial]
#[test]
fn feed_events_q_quits_from_login_when_profile_focus_empty_vault() {
    let dir = tempfile::tempdir().expect("tempdir");
    temp_env::with_var("TSAFE_VAULT_DIR", Some(dir.path().as_os_str()), || {
        let mut app = App::new();
        app.update_rx = None;
        app.update_available = None;
        assert!(app.profiles.is_empty());
        let mut pw = None;
        let quit = feed_events(
            &mut app,
            [key(KeyCode::Char('q'), KeyModifiers::NONE)],
            &mut pw,
        );
        assert!(quit);
    });
}

#[serial]
#[test]
fn feed_events_login_empty_enter_without_pending_keyring_shows_os_unlock_guidance() {
    let dir = tempfile::tempdir().expect("tempdir");
    temp_env::with_var("TSAFE_VAULT_DIR", Some(dir.path().as_os_str()), || {
        let mut app = App::new_for_test(vec!["default".into()], Screen::Login);
        app.update_rx = None;
        app.update_available = None;
        let mut pw = None;
        let quit = feed_events(&mut app, [key(KeyCode::Enter, KeyModifiers::NONE)], &mut pw);
        assert!(!quit);
        assert_eq!(app.screen, Screen::Login);
        assert!(app.password_buf.is_empty());
        let err = app
            .login_error
            .as_deref()
            .expect("expected empty-enter guidance when run_loop has not primed OS unlock");
        assert!(
            err.contains("tsafe biometric enable"),
            "unexpected login error: {err}"
        );
        assert!(
            err.contains("leave the field empty, press Enter"),
            "unexpected login error: {err}"
        );
        assert!(
            err.contains("Touch ID / OS unlock"),
            "unexpected login error: {err}"
        );
    });
}

#[serial]
#[test]
fn feed_events_login_empty_enter_guidance_clears_when_user_starts_typing() {
    let dir = tempfile::tempdir().expect("tempdir");
    temp_env::with_var("TSAFE_VAULT_DIR", Some(dir.path().as_os_str()), || {
        let mut app = App::new_for_test(vec!["default".into()], Screen::Login);
        app.update_rx = None;
        app.update_available = None;
        let mut pw = None;
        let quit = feed_events(
            &mut app,
            [
                key(KeyCode::Enter, KeyModifiers::NONE),
                key(KeyCode::Char('x'), KeyModifiers::NONE),
            ],
            &mut pw,
        );
        assert!(!quit);
        assert_eq!(app.screen, Screen::Login);
        assert_eq!(app.password_buf.as_str(), "x");
        assert_eq!(app.login_focus, tsafe_tui::app::LoginFocus::Password);
        assert!(
            app.login_error.is_none(),
            "typing after empty-enter guidance should clear the OS-unlock hint:\n{:?}",
            app.login_error
        );
    });
}

#[serial]
#[test]
fn feed_events_login_typed_password_enter_does_not_reuse_empty_enter_guidance() {
    let dir = tempfile::tempdir().expect("tempdir");
    temp_env::with_var("TSAFE_VAULT_DIR", Some(dir.path().as_os_str()), || {
        let mut app = App::new_for_test(vec!["default".into()], Screen::Login);
        app.update_rx = None;
        app.update_available = None;
        let mut pw = None;
        let quit = feed_events(
            &mut app,
            [
                key(KeyCode::Char('x'), KeyModifiers::NONE),
                key(KeyCode::Enter, KeyModifiers::NONE),
            ],
            &mut pw,
        );
        assert!(!quit);
        assert_eq!(app.screen, Screen::Login);
        let err = app
            .login_error
            .as_deref()
            .expect("expected a normal login failure for typed-password Enter");
        assert!(
            !err.contains("leave the field empty, press Enter"),
            "typed-password Enter should not recycle the empty-enter quick-unlock guidance:\n{err}"
        );
        assert!(
            !err.contains("Touch ID / OS unlock"),
            "typed-password Enter should stay on the normal login path, not the OS-unlock hint path:\n{err}"
        );
    });
}

#[serial]
#[test]
fn feed_events_dashboard_help_then_esc() {
    let dir = tempfile::tempdir().expect("tempdir");
    temp_env::with_var("TSAFE_VAULT_DIR", Some(dir.path().as_os_str()), || {
        let mut app = app_dashboard_demo_empty(App::new());
        let mut pw = None;
        let quit = feed_events(
            &mut app,
            [
                key(KeyCode::Char('?'), KeyModifiers::NONE),
                key(KeyCode::Esc, KeyModifiers::NONE),
            ],
            &mut pw,
        );
        assert!(!quit);
        assert!(!app.help_visible);
        assert_eq!(app.screen, Screen::Dashboard);
    });
}

#[serial]
#[test]
fn feed_events_dashboard_new_secret_then_esc_returns_to_dashboard() {
    let dir = tempfile::tempdir().expect("tempdir");
    temp_env::with_var("TSAFE_VAULT_DIR", Some(dir.path().as_os_str()), || {
        let mut app = app_dashboard_demo_empty(App::new());
        let mut pw = None;
        let quit = feed_events(
            &mut app,
            [
                key(KeyCode::Char('n'), KeyModifiers::NONE),
                key(KeyCode::Esc, KeyModifiers::NONE),
            ],
            &mut pw,
        );
        assert!(!quit);
        assert_eq!(app.screen, Screen::Dashboard);
    });
}
