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

use crate::core::agent::{ClaudeCodeAdapter, CodexAdapter};
use crate::core::store::Store;
use crate::core::Result;

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

pub enum Screen {
    Auth(AuthScreen),
    List(ListScreen),
}

pub struct App {
    pub screen: Screen,
    pub should_quit: bool,
    pub store: Store,
}

impl App {
    pub fn new(store: Store) -> Result<Self> {
        let screen = if store.is_authenticated() {
            Screen::List(ListScreen::load(&store)?)
        } else {
            Screen::Auth(AuthScreen::new())
        };
        Ok(Self {
            screen,
            should_quit: false,
            store,
        })
    }
}

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::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::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 filter_mode {
                            match key.code {
                                KeyCode::Char(c) => screen.filter.push(c),
                                KeyCode::Backspace => {
                                    screen.filter.pop();
                                }
                                KeyCode::Esc => {
                                    filter_mode = false;
                                    screen.filter.clear();
                                }
                                KeyCode::Enter => {
                                    filter_mode = false;
                                }
                                _ => {}
                            }
                        } else {
                            match key.code {
                                KeyCode::Char('q') => app.should_quit = true,
                                KeyCode::Char('j') | KeyCode::Down => screen.move_down(),
                                KeyCode::Char('k') | KeyCode::Up => screen.move_up(),
                                KeyCode::Char('/') => filter_mode = true,
                                KeyCode::Char('s') | KeyCode::Enter => {
                                    // Extract name first to release immutable borrow before mutate
                                    let selected_info = {
                                        let filtered = screen.filtered();
                                        filtered.get(screen.selected)
                                            .map(|p| (p.name().to_string(), p.target().to_string()))
                                    };
                                    if let Some((name, target)) = selected_info {
                                        // Load provider from store by name to get full Provider
                                        let provider_opt = screen.providers.iter()
                                            .find(|p| p.name() == name && p.target() == target)
                                            .cloned();
                                        if let Some(provider) = provider_opt {
                                            match apply_provider_tui(&app.store, &provider) {
                                                Ok(()) => {
                                                    if let Ok(new_state) = app.store.load_state() {
                                                        screen.state = new_state;
                                                    }
                                                    screen.status = Some(format!(
                                                        "已切换到 {} | 端点信号良好",
                                                        name
                                                    ));
                                                }
                                                Err(e) => {
                                                    screen.status = Some(format!("切换失败: {}", e));
                                                }
                                            }
                                        }
                                    }
                                }
                                _ => {}
                            }
                        }
                    }
                }
            }
        }
    }
    Ok(())
}

fn apply_provider_tui(store: &Store, provider: &crate::core::provider::Provider) -> Result<()> {
    use crate::core::agent::Agent;

    match provider.target() {
        "claude-code" => {
            let config_path = dirs::home_dir()
                .unwrap_or_else(|| PathBuf::from("."))
                .join(".claude")
                .join("settings.json");
            let adapter = ClaudeCodeAdapter::new(&config_path);
            adapter.apply(provider)?;
        }
        "codex" => {
            let home = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
            let adapter = CodexAdapter::new(
                &home.join(".codex").join("config.toml"),
                &home.join(".codex").join("auth.json"),
            );
            adapter.apply(provider)?;
        }
        _ => {}
    }

    let mut state = store.load_state()?;
    state.insert(provider.target().to_string(), Some(provider.name().to_string()));
    store.save_state(&state)?;

    Ok(())
}
