use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use ratatui::{
    layout::{Constraint, Layout, Rect},
    style::{Color, Modifier, Style},
    text::{Line, Span},
    widgets::Paragraph,
    Frame,
};
use sqlx::sqlite::SqlitePool;
use tokio::sync::mpsc;

use crate::app::{AppMessage, NotifyLevel};
use crate::config::Settings;

// =============================================================================
// Types
// =============================================================================

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SettingsFocus {
    TeamAbbrev,
    TeamSeason,
    MajorSlots,
    MinorSlots,
    ApiUrl,
    ApiKey,
    SaveButton,
    ResetButton,
}

impl SettingsFocus {
    fn next(self) -> Self {
        match self {
            Self::TeamAbbrev => Self::TeamSeason,
            Self::TeamSeason => Self::MajorSlots,
            Self::MajorSlots => Self::MinorSlots,
            Self::MinorSlots => Self::ApiUrl,
            Self::ApiUrl => Self::ApiKey,
            Self::ApiKey => Self::SaveButton,
            Self::SaveButton => Self::ResetButton,
            Self::ResetButton => Self::TeamAbbrev,
        }
    }

    fn prev(self) -> Self {
        match self {
            Self::TeamAbbrev => Self::ResetButton,
            Self::TeamSeason => Self::TeamAbbrev,
            Self::MajorSlots => Self::TeamSeason,
            Self::MinorSlots => Self::MajorSlots,
            Self::ApiUrl => Self::MinorSlots,
            Self::ApiKey => Self::ApiUrl,
            Self::SaveButton => Self::ApiKey,
            Self::ResetButton => Self::SaveButton,
        }
    }

    fn is_text_input(self) -> bool {
        matches!(
            self,
            Self::TeamAbbrev
                | Self::TeamSeason
                | Self::MajorSlots
                | Self::MinorSlots
                | Self::ApiUrl
                | Self::ApiKey
        )
    }
}

// =============================================================================
// State
// =============================================================================

pub struct SettingsState {
    // Text inputs
    pub abbrev: String,
    pub season_str: String,
    pub major_slots_str: String,
    pub minor_slots_str: String,
    pub base_url: String,
    pub api_key: String,
    pub api_key_visible: bool,

    // Validation
    pub team_info: Option<String>,

    // UI
    pub focus: SettingsFocus,
    pub has_unsaved_changes: bool,

    // Original settings for change detection
    original: SettingsSnapshot,
}

#[derive(Clone)]
struct SettingsSnapshot {
    abbrev: String,
    season_str: String,
    major_slots_str: String,
    minor_slots_str: String,
    base_url: String,
    api_key: String,
}

impl SettingsState {
    pub fn new(settings: &Settings) -> Self {
        let abbrev = settings.team.abbrev.clone();
        let season_str = settings.team.season.to_string();
        let major_slots_str = settings.team.major_league_slots.to_string();
        let minor_slots_str = settings.team.minor_league_slots.to_string();
        let base_url = settings.api.base_url.clone();
        let api_key = settings.api.api_key.clone();
        let original = SettingsSnapshot {
            abbrev: abbrev.clone(),
            season_str: season_str.clone(),
            major_slots_str: major_slots_str.clone(),
            minor_slots_str: minor_slots_str.clone(),
            base_url: base_url.clone(),
            api_key: api_key.clone(),
        };
        Self {
            abbrev,
            season_str,
            major_slots_str,
            minor_slots_str,
            base_url,
            api_key,
            api_key_visible: false,
            team_info: None,
            focus: SettingsFocus::TeamAbbrev,
            has_unsaved_changes: false,
            original,
        }
    }

    pub fn is_input_captured(&self) -> bool {
        self.focus.is_text_input()
    }

    fn current_snapshot(&self) -> SettingsSnapshot {
        SettingsSnapshot {
            abbrev: self.abbrev.clone(),
            season_str: self.season_str.clone(),
            major_slots_str: self.major_slots_str.clone(),
            minor_slots_str: self.minor_slots_str.clone(),
            base_url: self.base_url.clone(),
            api_key: self.api_key.clone(),
        }
    }

    pub fn handle_key(
        &mut self,
        key: KeyEvent,
        pool: &SqlitePool,
        _settings: &Settings,
        tx: &mpsc::UnboundedSender<AppMessage>,
    ) {
        // Ctrl+S: save from anywhere
        if key.modifiers.contains(KeyModifiers::CONTROL) && key.code == KeyCode::Char('s') {
            self.save_settings(tx);
            return;
        }

        // Tab / Shift+Tab navigation
        if key.code == KeyCode::Tab {
            if key.modifiers.contains(KeyModifiers::SHIFT) {
                self.focus = self.focus.prev();
            } else {
                self.focus = self.focus.next();
            }
            return;
        }

        // Esc exits text input focus to save button
        if key.code == KeyCode::Esc && self.focus.is_text_input() {
            self.focus = SettingsFocus::SaveButton;
            return;
        }

        // Text input handling
        if self.focus.is_text_input() {
            match key.code {
                KeyCode::Char('t')
                    if self.focus == SettingsFocus::ApiKey
                        && key.modifiers.contains(KeyModifiers::CONTROL) =>
                {
                    self.api_key_visible = !self.api_key_visible;
                    return;
                }
                KeyCode::Char(c) => {
                    self.insert_char(c);
                    self.check_unsaved();
                    // Validate team on abbrev/season change
                    if matches!(self.focus, SettingsFocus::TeamAbbrev | SettingsFocus::TeamSeason) {
                        self.validate_team(pool, tx);
                    }
                }
                KeyCode::Backspace => {
                    self.delete_char();
                    self.check_unsaved();
                    if matches!(self.focus, SettingsFocus::TeamAbbrev | SettingsFocus::TeamSeason) {
                        self.validate_team(pool, tx);
                    }
                }
                _ => {}
            }
            return;
        }

        // Button handling
        match self.focus {
            SettingsFocus::SaveButton => {
                if key.code == KeyCode::Enter {
                    self.save_settings(tx);
                }
            }
            SettingsFocus::ResetButton => {
                if key.code == KeyCode::Enter {
                    self.reset_to_defaults();
                    let _ = tx.send(AppMessage::Notify(
                        "Reset to defaults".to_string(),
                        NotifyLevel::Info,
                    ));
                }
            }
            _ => {}
        }
    }

    fn insert_char(&mut self, c: char) {
        match self.focus {
            SettingsFocus::TeamAbbrev => self.abbrev.push(c),
            SettingsFocus::TeamSeason => {
                if c.is_ascii_digit() {
                    self.season_str.push(c);
                }
            }
            SettingsFocus::MajorSlots => {
                if c.is_ascii_digit() {
                    self.major_slots_str.push(c);
                }
            }
            SettingsFocus::MinorSlots => {
                if c.is_ascii_digit() {
                    self.minor_slots_str.push(c);
                }
            }
            SettingsFocus::ApiUrl => self.base_url.push(c),
            SettingsFocus::ApiKey => self.api_key.push(c),
            _ => {}
        }
    }

    fn delete_char(&mut self) {
        match self.focus {
            SettingsFocus::TeamAbbrev => { self.abbrev.pop(); }
            SettingsFocus::TeamSeason => { self.season_str.pop(); }
            SettingsFocus::MajorSlots => { self.major_slots_str.pop(); }
            SettingsFocus::MinorSlots => { self.minor_slots_str.pop(); }
            SettingsFocus::ApiUrl => { self.base_url.pop(); }
            SettingsFocus::ApiKey => { self.api_key.pop(); }
            SettingsFocus::SaveButton | SettingsFocus::ResetButton => {}
        }
    }

    fn check_unsaved(&mut self) {
        let snap = self.current_snapshot();
        self.has_unsaved_changes = snap.abbrev != self.original.abbrev
            || snap.season_str != self.original.season_str
            || snap.major_slots_str != self.original.major_slots_str
            || snap.minor_slots_str != self.original.minor_slots_str
            || snap.base_url != self.original.base_url
            || snap.api_key != self.original.api_key;
    }

    fn validate_team(&self, pool: &SqlitePool, tx: &mpsc::UnboundedSender<AppMessage>) {
        let abbrev = self.abbrev.clone();
        let season: i64 = self.season_str.parse().unwrap_or(0);
        if abbrev.is_empty() || season == 0 {
            return;
        }

        let pool = pool.clone();
        let tx = tx.clone();
        tokio::spawn(async move {
            let result = crate::db::queries::get_team_by_abbrev(&pool, &abbrev, season)
                .await
                .ok()
                .flatten()
                .map(|team| {
                    let name = if team.long_name.is_empty() {
                        team.short_name
                    } else {
                        team.long_name
                    };
                    (name, team.salary_cap)
                });
            let _ = tx.send(AppMessage::SettingsTeamValidated(result));
        });
    }

    fn save_settings(&mut self, tx: &mpsc::UnboundedSender<AppMessage>) {
        let season: i32 = match self.season_str.parse() {
            Ok(v) => v,
            Err(_) => {
                let _ = tx.send(AppMessage::Notify(
                    "Invalid season number".to_string(),
                    NotifyLevel::Error,
                ));
                return;
            }
        };
        let major_slots: usize = self.major_slots_str.parse().unwrap_or(26);
        let minor_slots: usize = self.minor_slots_str.parse().unwrap_or(6);

        let settings = Settings {
            db_path: std::path::PathBuf::from("data/sba_scout.db"),
            api: crate::config::ApiSettings {
                base_url: self.base_url.clone(),
                api_key: self.api_key.clone(),
                timeout: 30,
            },
            team: crate::config::TeamSettings {
                abbrev: self.abbrev.clone(),
                season,
                major_league_slots: major_slots,
                minor_league_slots: minor_slots,
            },
            ui: crate::config::UiSettings::default(),
            rating_weights: crate::config::RatingWeights::default(),
        };

        match toml::to_string_pretty(&settings) {
            Ok(toml_str) => match std::fs::write("settings.toml", &toml_str) {
                Ok(_) => {
                    self.has_unsaved_changes = false;
                    self.original = self.current_snapshot();
                    let _ = tx.send(AppMessage::Notify(
                        "Settings saved to settings.toml (restart to apply)".to_string(),
                        NotifyLevel::Success,
                    ));
                }
                Err(e) => {
                    let _ = tx.send(AppMessage::Notify(
                        format!("Failed to write settings.toml: {e}"),
                        NotifyLevel::Error,
                    ));
                }
            },
            Err(e) => {
                let _ = tx.send(AppMessage::Notify(
                    format!("Failed to serialize settings: {e}"),
                    NotifyLevel::Error,
                ));
            }
        }
    }

    fn reset_to_defaults(&mut self) {
        let defaults = Settings::default();
        self.abbrev = defaults.team.abbrev;
        self.season_str = defaults.team.season.to_string();
        self.major_slots_str = defaults.team.major_league_slots.to_string();
        self.minor_slots_str = defaults.team.minor_league_slots.to_string();
        self.base_url = defaults.api.base_url;
        self.api_key = defaults.api.api_key;
        self.has_unsaved_changes = true;
        self.team_info = None;
    }

    pub fn handle_message(&mut self, msg: AppMessage) {
        if let AppMessage::SettingsTeamValidated(result) = msg {
            self.team_info = match result {
                Some((name, cap)) => {
                    let cap_str = cap.map(|c| format!(" (Cap: {:.2})", c)).unwrap_or_default();
                    Some(format!("{}{}", name, cap_str))
                }
                None => Some("Team not found".to_string()),
            };
        }
    }

    // =========================================================================
    // Rendering
    // =========================================================================

    pub fn render(&self, frame: &mut Frame, area: Rect) {
        let chunks = Layout::vertical([
            Constraint::Length(1),  // title
            Constraint::Length(1),  // spacer
            Constraint::Length(1),  // "Team" section header
            Constraint::Length(1),  // abbrev + season
            Constraint::Length(1),  // team validation
            Constraint::Length(1),  // major/minor slots
            Constraint::Length(1),  // spacer
            Constraint::Length(1),  // "API" section header
            Constraint::Length(1),  // base URL
            Constraint::Length(1),  // api key
            Constraint::Length(1),  // spacer
            Constraint::Length(1),  // buttons
            Constraint::Min(0),    // spacer
            Constraint::Length(1),  // hints
        ])
        .split(area);

        // Title
        let title = " Settings";
        frame.render_widget(
            Paragraph::new(title)
                .style(Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD)),
            chunks[0],
        );

        // Team section
        frame.render_widget(
            Paragraph::new(" Team").style(Style::default().fg(Color::White).add_modifier(Modifier::BOLD)),
            chunks[2],
        );

        // Abbrev + Season on same row
        let team_row = Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
            .split(chunks[3]);

        self.render_input(frame, team_row[0], "Abbreviation", &self.abbrev, SettingsFocus::TeamAbbrev, false, self.abbrev != self.original.abbrev);
        self.render_input(frame, team_row[1], "Season", &self.season_str, SettingsFocus::TeamSeason, false, self.season_str != self.original.season_str);

        // Team validation
        let team_info_style = if self.team_info.as_deref() == Some("Team not found") {
            Style::default().fg(Color::Red)
        } else {
            Style::default().fg(Color::Green)
        };
        let team_info_text = self
            .team_info
            .as_ref()
            .map(|s| format!("   → {}", s))
            .unwrap_or_default();
        frame.render_widget(Paragraph::new(team_info_text).style(team_info_style), chunks[4]);

        // Major/Minor slots
        let slots_row = Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
            .split(chunks[5]);
        self.render_input(frame, slots_row[0], "Major Slots", &self.major_slots_str, SettingsFocus::MajorSlots, false, self.major_slots_str != self.original.major_slots_str);
        self.render_input(frame, slots_row[1], "Minor Slots", &self.minor_slots_str, SettingsFocus::MinorSlots, false, self.minor_slots_str != self.original.minor_slots_str);

        // API section
        frame.render_widget(
            Paragraph::new(" API").style(Style::default().fg(Color::White).add_modifier(Modifier::BOLD)),
            chunks[7],
        );

        self.render_input(frame, chunks[8], "Base URL", &self.base_url, SettingsFocus::ApiUrl, false, self.base_url != self.original.base_url);
        let api_key_display = if self.api_key_visible {
            self.api_key.clone()
        } else {
            "•".repeat(self.api_key.len().min(20))
        };
        self.render_input(frame, chunks[9], "API Key", &api_key_display, SettingsFocus::ApiKey, true, self.api_key != self.original.api_key);

        // Buttons
        let button_row = Layout::horizontal([
            Constraint::Length(12),
            Constraint::Length(2),
            Constraint::Length(22),
            Constraint::Min(0),
        ])
        .split(chunks[11]);

        let save_style = if self.focus == SettingsFocus::SaveButton {
            Style::default().fg(Color::Black).bg(Color::Cyan).add_modifier(Modifier::BOLD)
        } else {
            Style::default().fg(Color::Cyan)
        };
        let reset_style = if self.focus == SettingsFocus::ResetButton {
            Style::default().fg(Color::Black).bg(Color::Yellow).add_modifier(Modifier::BOLD)
        } else {
            Style::default().fg(Color::Yellow)
        };

        frame.render_widget(Paragraph::new("  [ Save ]  ").style(save_style), button_row[0]);
        frame.render_widget(Paragraph::new("  [ Reset to Defaults ]").style(reset_style), button_row[2]);

        // Hints
        let hint_base = if self.focus == SettingsFocus::ApiKey {
            " [Tab] Next  [Shift+Tab] Prev  [Ctrl+T] Toggle key  [Ctrl+S] Save  [Esc] Buttons"
        } else if self.focus.is_text_input() {
            " [Tab] Next  [Shift+Tab] Prev  [Ctrl+S] Save  [Esc] Buttons"
        } else {
            " [Tab] Next  [Enter] Activate  [Ctrl+S] Save"
        };
        let mut spans = vec![Span::styled(hint_base, Style::default().fg(Color::DarkGray))];
        if self.has_unsaved_changes {
            spans.push(Span::styled(
                "  * unsaved changes",
                Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD),
            ));
        }
        frame.render_widget(Paragraph::new(Line::from(spans)), chunks[13]);
    }

    fn render_input(
        &self,
        frame: &mut Frame,
        area: Rect,
        label: &str,
        value: &str,
        target_focus: SettingsFocus,
        is_password: bool,
        changed: bool,
    ) {
        let is_focused = self.focus == target_focus;
        let label_style = Style::default().fg(Color::DarkGray);
        let value_style = if is_focused {
            Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)
        } else {
            Style::default().fg(Color::White)
        };

        let cursor = if is_focused { "▏" } else { "" };
        let change_marker = if changed { "* " } else { "  " };
        let toggle_hint = if is_password && is_focused { " [Ctrl+T]" } else { "" };

        let line = Line::from(vec![
            Span::styled(change_marker, Style::default().fg(Color::Yellow)),
            Span::styled(format!(" {}: ", label), label_style),
            Span::styled(format!("[{}{}]", value, cursor), value_style),
            Span::styled(toggle_hint, Style::default().fg(Color::DarkGray)),
        ]);

        frame.render_widget(Paragraph::new(line), area);
    }
}
