use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::OnceLock;

use ratatui::style::{Color, Modifier, Style};

/// Available themes
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ThemeName {
    Hacker,
    GruvboxDark,
    CatppuccinMocha,
    CatppuccinLatte,
    TokyoNight,
    Dracula,
    Nord,
}

impl ThemeName {
    pub const ALL: &'static [ThemeName] = &[
        ThemeName::Hacker,
        ThemeName::GruvboxDark,
        ThemeName::CatppuccinMocha,
        ThemeName::CatppuccinLatte,
        ThemeName::TokyoNight,
        ThemeName::Dracula,
        ThemeName::Nord,
    ];

    pub fn label(self) -> &'static str {
        match self {
            ThemeName::Hacker => "hacker",
            ThemeName::GruvboxDark => "gruvbox",
            ThemeName::CatppuccinMocha => "catppuccin-mocha",
            ThemeName::CatppuccinLatte => "catppuccin-latte",
            ThemeName::TokyoNight => "tokyo-night",
            ThemeName::Dracula => "dracula",
            ThemeName::Nord => "nord",
        }
    }

    pub fn display(self) -> &'static str {
        match self {
            ThemeName::Hacker => "Hacker",
            ThemeName::GruvboxDark => "Gruvbox Dark",
            ThemeName::CatppuccinMocha => "Catppuccin Mocha",
            ThemeName::CatppuccinLatte => "Catppuccin Latte",
            ThemeName::TokyoNight => "Tokyo Night",
            ThemeName::Dracula => "Dracula",
            ThemeName::Nord => "Nord",
        }
    }

    pub fn from_str(s: &str) -> Option<ThemeName> {
        match s.to_lowercase().trim() {
            "hacker" | "default" => Some(ThemeName::Hacker),
            "gruvbox" | "gruvbox-dark" | "gruvbox_dark" => Some(ThemeName::GruvboxDark),
            "catppuccin-mocha" | "catppuccin_mocha" | "mocha" => Some(ThemeName::CatppuccinMocha),
            "catppuccin-latte" | "catppuccin_latte" | "latte" => Some(ThemeName::CatppuccinLatte),
            "tokyo-night" | "tokyo_night" | "tokyonight" => Some(ThemeName::TokyoNight),
            "dracula" => Some(ThemeName::Dracula),
            "nord" => Some(ThemeName::Nord),
            _ => None,
        }
    }

    fn index(self) -> usize {
        ThemeName::ALL.iter().position(|&t| t == self).unwrap()
    }

    fn from_index(i: usize) -> ThemeName {
        ThemeName::ALL[i % ThemeName::ALL.len()]
    }
}

/// Centralized theme for the entire application
pub struct Theme {
    // ── Base ─────────────────────────────────
    pub bg: Color,
    pub fg: Color,

    // ── Headers & titles ────────────────────
    pub title: Style,
    pub header: Style,

    // ── Selection ───────────────────────────
    pub selected: Style,
    pub selected_unfocused: Style,

    // ── Status indicators ───────────────────
    pub status_ok: Style,
    pub status_error: Style,
    pub status_warning: Style,
    pub status_info: Style,

    // ── Plugin types ────────────────────────
    pub vst2: Style,
    pub vst3: Style,
    pub clap: Style,

    // ── Borders ─────────────────────────────
    pub border: Style,
    pub border_focused: Style,

    // ── Tabs ────────────────────────────────
    pub tab_active: Style,
    pub tab_inactive: Style,

    // ── Status bar ──────────────────────────
    pub status_bar: Style,
    pub status_bar_key: Style,

    // ── Popup ───────────────────────────────
    pub popup_border: Style,
    pub popup_title: Style,

    // ── Log ─────────────────────────────────
    pub log_info: Style,
    pub log_error: Style,
    pub log_success: Style,

    // ── Spinner ─────────────────────────────
    pub spinner: Style,

    // ── Filter highlight ────────────────────
    pub filter_match: Style,
}

// ── Static theme storage ──────────────────────────────────

static THEMES: OnceLock<Vec<Theme>> = OnceLock::new();
static ACTIVE: AtomicUsize = AtomicUsize::new(0);

fn all_themes() -> &'static Vec<Theme> {
    THEMES.get_or_init(|| {
        vec![
            build_hacker(),
            build_gruvbox_dark(),
            build_catppuccin_mocha(),
            build_catppuccin_latte(),
            build_tokyo_night(),
            build_dracula(),
            build_nord(),
        ]
    })
}

/// Get the current theme
pub fn theme() -> &'static Theme {
    &all_themes()[ACTIVE.load(Ordering::Relaxed)]
}

/// Get the current theme name
pub fn theme_name() -> ThemeName {
    ThemeName::from_index(ACTIVE.load(Ordering::Relaxed))
}

/// Cycle to the next theme, return its name
pub fn cycle_theme() -> ThemeName {
    let _ = all_themes(); // ensure initialized
    let count = ThemeName::ALL.len();
    let old = ACTIVE.load(Ordering::Relaxed);
    let new = (old + 1) % count;
    ACTIVE.store(new, Ordering::Relaxed);
    ThemeName::from_index(new)
}

/// Set a specific theme by name. Returns true if found.
pub fn set_theme(name: ThemeName) {
    let _ = all_themes(); // ensure initialized
    ACTIVE.store(name.index(), Ordering::Relaxed);
}

// ── Theme constructors ────────────────────────────────────

fn build_hacker() -> Theme {
    Theme {
        bg: Color::Reset,
        fg: Color::White,

        title: Style::new().fg(Color::Cyan).add_modifier(Modifier::BOLD),
        header: Style::new().fg(Color::Yellow).add_modifier(Modifier::BOLD),

        selected: Style::new()
            .bg(Color::Rgb(40, 40, 60))
            .fg(Color::Cyan)
            .add_modifier(Modifier::BOLD),
        selected_unfocused: Style::new().bg(Color::Rgb(30, 30, 40)).fg(Color::DarkGray),

        status_ok: Style::new().fg(Color::Green),
        status_error: Style::new().fg(Color::Red).add_modifier(Modifier::BOLD),
        status_warning: Style::new().fg(Color::Yellow),
        status_info: Style::new().fg(Color::Cyan),

        vst2: Style::new().fg(Color::Rgb(100, 180, 255)),
        vst3: Style::new().fg(Color::Rgb(180, 130, 255)),
        clap: Style::new().fg(Color::Rgb(255, 180, 100)),

        border: Style::new().fg(Color::Rgb(60, 60, 80)),
        border_focused: Style::new().fg(Color::Cyan),

        tab_active: Style::new()
            .fg(Color::Cyan)
            .add_modifier(Modifier::BOLD)
            .add_modifier(Modifier::UNDERLINED),
        tab_inactive: Style::new().fg(Color::DarkGray),

        status_bar: Style::new().bg(Color::Rgb(25, 25, 35)).fg(Color::DarkGray),
        status_bar_key: Style::new().fg(Color::Cyan).add_modifier(Modifier::BOLD),

        popup_border: Style::new().fg(Color::Yellow),
        popup_title: Style::new().fg(Color::Yellow).add_modifier(Modifier::BOLD),

        log_info: Style::new().fg(Color::White),
        log_error: Style::new().fg(Color::Red),
        log_success: Style::new().fg(Color::Green),

        spinner: Style::new().fg(Color::Cyan),
        filter_match: Style::new().fg(Color::Yellow).add_modifier(Modifier::BOLD),
    }
}

fn build_gruvbox_dark() -> Theme {
    // Gruvbox Dark palette
    let bg0 = Color::Rgb(40, 40, 40); // #282828
    let bg1 = Color::Rgb(60, 56, 54); // #3c3836
    let bg2 = Color::Rgb(80, 73, 69); // #504945
    let fg0 = Color::Rgb(251, 241, 199); // #fbf1c7
    let fg1 = Color::Rgb(235, 219, 178); // #ebdbb2
    let gray = Color::Rgb(146, 131, 116); // #928374
    let red = Color::Rgb(251, 73, 52); // #fb4934
    let green = Color::Rgb(184, 187, 38); // #b8bb26
    let yellow = Color::Rgb(250, 189, 47); // #fabd2f
    let blue = Color::Rgb(131, 165, 152); // #83a598
    let purple = Color::Rgb(211, 134, 155); // #d3869b
    let aqua = Color::Rgb(142, 192, 124); // #8ec07c
    let orange = Color::Rgb(254, 128, 25); // #fe8019

    Theme {
        bg: bg0,
        fg: fg1,

        title: Style::new().fg(orange).add_modifier(Modifier::BOLD),
        header: Style::new().fg(yellow).add_modifier(Modifier::BOLD),

        selected: Style::new().bg(bg2).fg(fg0).add_modifier(Modifier::BOLD),
        selected_unfocused: Style::new().bg(bg1).fg(gray),

        status_ok: Style::new().fg(green),
        status_error: Style::new().fg(red).add_modifier(Modifier::BOLD),
        status_warning: Style::new().fg(yellow),
        status_info: Style::new().fg(aqua),

        vst2: Style::new().fg(blue),
        vst3: Style::new().fg(purple),
        clap: Style::new().fg(orange),

        border: Style::new().fg(bg2),
        border_focused: Style::new().fg(orange),

        tab_active: Style::new()
            .fg(orange)
            .add_modifier(Modifier::BOLD)
            .add_modifier(Modifier::UNDERLINED),
        tab_inactive: Style::new().fg(gray),

        status_bar: Style::new().bg(bg1).fg(gray),
        status_bar_key: Style::new().fg(yellow).add_modifier(Modifier::BOLD),

        popup_border: Style::new().fg(yellow),
        popup_title: Style::new().fg(yellow).add_modifier(Modifier::BOLD),

        log_info: Style::new().fg(fg1),
        log_error: Style::new().fg(red),
        log_success: Style::new().fg(green),

        spinner: Style::new().fg(aqua),
        filter_match: Style::new().fg(orange).add_modifier(Modifier::BOLD),
    }
}

fn build_catppuccin_mocha() -> Theme {
    // Catppuccin Mocha palette
    let base = Color::Rgb(30, 30, 46); // #1e1e2e
    let mantle = Color::Rgb(24, 24, 37); // #181825
    let surface0 = Color::Rgb(49, 50, 68); // #313244
    let surface1 = Color::Rgb(69, 71, 90); // #45475a
    let overlay0 = Color::Rgb(108, 112, 134); // #6c7086
    let text = Color::Rgb(205, 214, 244); // #cdd6f4
    let subtext0 = Color::Rgb(166, 173, 200); // #a6adc8
    let red = Color::Rgb(243, 139, 168); // #f38ba8
    let green = Color::Rgb(166, 227, 161); // #a6e3a1
    let yellow = Color::Rgb(249, 226, 175); // #f9e2af
    let blue = Color::Rgb(137, 180, 250); // #89b4fa
    let mauve = Color::Rgb(203, 166, 247); // #cba6f7
    let teal = Color::Rgb(148, 226, 213); // #94e2d5
    let lavender = Color::Rgb(180, 190, 254); // #b4befe
    let peach = Color::Rgb(250, 179, 135); // #fab387
    let pink = Color::Rgb(245, 194, 231); // #f5c2e7

    Theme {
        bg: base,
        fg: text,

        title: Style::new().fg(lavender).add_modifier(Modifier::BOLD),
        header: Style::new().fg(mauve).add_modifier(Modifier::BOLD),

        selected: Style::new()
            .bg(surface1)
            .fg(text)
            .add_modifier(Modifier::BOLD),
        selected_unfocused: Style::new().bg(surface0).fg(overlay0),

        status_ok: Style::new().fg(green),
        status_error: Style::new().fg(red).add_modifier(Modifier::BOLD),
        status_warning: Style::new().fg(yellow),
        status_info: Style::new().fg(teal),

        vst2: Style::new().fg(blue),
        vst3: Style::new().fg(mauve),
        clap: Style::new().fg(peach),

        border: Style::new().fg(surface1),
        border_focused: Style::new().fg(lavender),

        tab_active: Style::new()
            .fg(lavender)
            .add_modifier(Modifier::BOLD)
            .add_modifier(Modifier::UNDERLINED),
        tab_inactive: Style::new().fg(overlay0),

        status_bar: Style::new().bg(mantle).fg(subtext0),
        status_bar_key: Style::new().fg(lavender).add_modifier(Modifier::BOLD),

        popup_border: Style::new().fg(mauve),
        popup_title: Style::new().fg(mauve).add_modifier(Modifier::BOLD),

        log_info: Style::new().fg(text),
        log_error: Style::new().fg(red),
        log_success: Style::new().fg(green),

        spinner: Style::new().fg(teal),
        filter_match: Style::new().fg(pink).add_modifier(Modifier::BOLD),
    }
}

fn build_catppuccin_latte() -> Theme {
    // Catppuccin Latte palette (light theme)
    let base = Color::Rgb(239, 241, 245); // #eff1f5
    let mantle = Color::Rgb(230, 233, 239); // #e6e9ef
    let surface0 = Color::Rgb(204, 208, 218); // #ccd0da
    let surface1 = Color::Rgb(188, 192, 204); // #bcc0cc
    let overlay0 = Color::Rgb(156, 160, 176); // #9ca0b0
    let text = Color::Rgb(76, 79, 105); // #4c4f69
    let subtext0 = Color::Rgb(108, 111, 133); // #6c6f85
    let red = Color::Rgb(210, 15, 57); // #d20f39
    let green = Color::Rgb(64, 160, 43); // #40a02b
    let yellow = Color::Rgb(223, 142, 29); // #df8e1d
    let blue = Color::Rgb(30, 102, 245); // #1e66f5
    let mauve = Color::Rgb(136, 57, 239); // #8839ef
    let teal = Color::Rgb(23, 146, 153); // #179299
    let lavender = Color::Rgb(114, 135, 253); // #7287fd
    let peach = Color::Rgb(254, 100, 11); // #fe640b
    let pink = Color::Rgb(234, 118, 203); // #ea76cb

    Theme {
        bg: base,
        fg: text,

        title: Style::new().fg(lavender).add_modifier(Modifier::BOLD),
        header: Style::new().fg(mauve).add_modifier(Modifier::BOLD),

        selected: Style::new()
            .bg(surface1)
            .fg(text)
            .add_modifier(Modifier::BOLD),
        selected_unfocused: Style::new().bg(surface0).fg(overlay0),

        status_ok: Style::new().fg(green),
        status_error: Style::new().fg(red).add_modifier(Modifier::BOLD),
        status_warning: Style::new().fg(yellow),
        status_info: Style::new().fg(teal),

        vst2: Style::new().fg(blue),
        vst3: Style::new().fg(mauve),
        clap: Style::new().fg(peach),

        border: Style::new().fg(surface1),
        border_focused: Style::new().fg(lavender),

        tab_active: Style::new()
            .fg(lavender)
            .add_modifier(Modifier::BOLD)
            .add_modifier(Modifier::UNDERLINED),
        tab_inactive: Style::new().fg(overlay0),

        status_bar: Style::new().bg(mantle).fg(subtext0),
        status_bar_key: Style::new().fg(lavender).add_modifier(Modifier::BOLD),

        popup_border: Style::new().fg(mauve),
        popup_title: Style::new().fg(mauve).add_modifier(Modifier::BOLD),

        log_info: Style::new().fg(text),
        log_error: Style::new().fg(red),
        log_success: Style::new().fg(green),

        spinner: Style::new().fg(teal),
        filter_match: Style::new().fg(pink).add_modifier(Modifier::BOLD),
    }
}

fn build_tokyo_night() -> Theme {
    // Tokyo Night palette
    let bg = Color::Rgb(26, 27, 38); // #1a1b26
    let bg_dark = Color::Rgb(22, 22, 30); // #16161e
    let bg_highlight = Color::Rgb(41, 46, 66); // #292e42
    let terminal_black = Color::Rgb(65, 72, 104); // #414868
    let fg = Color::Rgb(169, 177, 214); // #a9b1d6
    let fg_dark = Color::Rgb(86, 95, 137); // #565f89
    let red = Color::Rgb(247, 118, 142); // #f7768e
    let green = Color::Rgb(158, 206, 106); // #9ece6a
    let yellow = Color::Rgb(224, 175, 104); // #e0af68
    let blue = Color::Rgb(122, 162, 247); // #7aa2f7
    let magenta = Color::Rgb(187, 154, 247); // #bb9af7
    let cyan = Color::Rgb(125, 207, 255); // #7dcfff
    let orange = Color::Rgb(255, 158, 100); // #ff9e64
    let teal = Color::Rgb(115, 218, 202); // #73daca

    Theme {
        bg,
        fg,

        title: Style::new().fg(blue).add_modifier(Modifier::BOLD),
        header: Style::new().fg(magenta).add_modifier(Modifier::BOLD),

        selected: Style::new()
            .bg(bg_highlight)
            .fg(fg)
            .add_modifier(Modifier::BOLD),
        selected_unfocused: Style::new().bg(Color::Rgb(33, 35, 48)).fg(fg_dark),

        status_ok: Style::new().fg(green),
        status_error: Style::new().fg(red).add_modifier(Modifier::BOLD),
        status_warning: Style::new().fg(yellow),
        status_info: Style::new().fg(cyan),

        vst2: Style::new().fg(blue),
        vst3: Style::new().fg(magenta),
        clap: Style::new().fg(orange),

        border: Style::new().fg(terminal_black),
        border_focused: Style::new().fg(blue),

        tab_active: Style::new()
            .fg(blue)
            .add_modifier(Modifier::BOLD)
            .add_modifier(Modifier::UNDERLINED),
        tab_inactive: Style::new().fg(fg_dark),

        status_bar: Style::new().bg(bg_dark).fg(fg_dark),
        status_bar_key: Style::new().fg(blue).add_modifier(Modifier::BOLD),

        popup_border: Style::new().fg(magenta),
        popup_title: Style::new().fg(magenta).add_modifier(Modifier::BOLD),

        log_info: Style::new().fg(fg),
        log_error: Style::new().fg(red),
        log_success: Style::new().fg(green),

        spinner: Style::new().fg(teal),
        filter_match: Style::new().fg(orange).add_modifier(Modifier::BOLD),
    }
}

fn build_dracula() -> Theme {
    // Dracula palette
    let bg = Color::Rgb(40, 42, 54); // #282a36
    let current_line = Color::Rgb(68, 71, 90); // #44475a
    let selection = Color::Rgb(68, 71, 90); // #44475a
    let fg = Color::Rgb(248, 248, 242); // #f8f8f2
    let comment = Color::Rgb(98, 114, 164); // #6272a4
    let cyan = Color::Rgb(139, 233, 253); // #8be9fd
    let green = Color::Rgb(80, 250, 123); // #50fa7b
    let orange = Color::Rgb(255, 184, 108); // #ffb86c
    let pink = Color::Rgb(255, 121, 198); // #ff79c6
    let purple = Color::Rgb(189, 147, 249); // #bd93f9
    let red = Color::Rgb(255, 85, 85); // #ff5555
    let yellow = Color::Rgb(241, 250, 140); // #f1fa8c

    Theme {
        bg,
        fg,

        title: Style::new().fg(purple).add_modifier(Modifier::BOLD),
        header: Style::new().fg(pink).add_modifier(Modifier::BOLD),

        selected: Style::new()
            .bg(selection)
            .fg(fg)
            .add_modifier(Modifier::BOLD),
        selected_unfocused: Style::new().bg(current_line).fg(comment),

        status_ok: Style::new().fg(green),
        status_error: Style::new().fg(red).add_modifier(Modifier::BOLD),
        status_warning: Style::new().fg(yellow),
        status_info: Style::new().fg(cyan),

        vst2: Style::new().fg(cyan),
        vst3: Style::new().fg(purple),
        clap: Style::new().fg(orange),

        border: Style::new().fg(comment),
        border_focused: Style::new().fg(purple),

        tab_active: Style::new()
            .fg(purple)
            .add_modifier(Modifier::BOLD)
            .add_modifier(Modifier::UNDERLINED),
        tab_inactive: Style::new().fg(comment),

        status_bar: Style::new().bg(current_line).fg(comment),
        status_bar_key: Style::new().fg(purple).add_modifier(Modifier::BOLD),

        popup_border: Style::new().fg(pink),
        popup_title: Style::new().fg(pink).add_modifier(Modifier::BOLD),

        log_info: Style::new().fg(fg),
        log_error: Style::new().fg(red),
        log_success: Style::new().fg(green),

        spinner: Style::new().fg(cyan),
        filter_match: Style::new().fg(green).add_modifier(Modifier::BOLD),
    }
}

fn build_nord() -> Theme {
    // Nord palette
    let polar0 = Color::Rgb(46, 52, 64); // #2e3440 (bg)
    let polar1 = Color::Rgb(59, 66, 82); // #3b4252
    let polar2 = Color::Rgb(67, 76, 94); // #434c5e
    let polar3 = Color::Rgb(76, 86, 106); // #4c566a
    let snow0 = Color::Rgb(216, 222, 233); // #d8dee9
    let snow1 = Color::Rgb(229, 233, 240); // #e5e9f0
    let frost0 = Color::Rgb(143, 188, 187); // #8fbcbb
    let frost1 = Color::Rgb(136, 192, 208); // #88c0d0
    let frost2 = Color::Rgb(129, 161, 193); // #81a1c1
                                            // frost3 (#5e81ac) available but unused
    let aurora_red = Color::Rgb(191, 97, 106); // #bf616a
    let aurora_orange = Color::Rgb(208, 135, 112); // #d08770
    let aurora_yellow = Color::Rgb(235, 203, 139); // #ebcb8b
    let aurora_green = Color::Rgb(163, 190, 140); // #a3be8c
    let aurora_purple = Color::Rgb(180, 142, 173); // #b48ead

    Theme {
        bg: polar0,
        fg: snow0,

        title: Style::new().fg(frost1).add_modifier(Modifier::BOLD),
        header: Style::new().fg(frost0).add_modifier(Modifier::BOLD),

        selected: Style::new()
            .bg(polar2)
            .fg(snow1)
            .add_modifier(Modifier::BOLD),
        selected_unfocused: Style::new().bg(polar1).fg(polar3),

        status_ok: Style::new().fg(aurora_green),
        status_error: Style::new().fg(aurora_red).add_modifier(Modifier::BOLD),
        status_warning: Style::new().fg(aurora_yellow),
        status_info: Style::new().fg(frost1),

        vst2: Style::new().fg(frost2),
        vst3: Style::new().fg(aurora_purple),
        clap: Style::new().fg(aurora_orange),

        border: Style::new().fg(polar2),
        border_focused: Style::new().fg(frost1),

        tab_active: Style::new()
            .fg(frost1)
            .add_modifier(Modifier::BOLD)
            .add_modifier(Modifier::UNDERLINED),
        tab_inactive: Style::new().fg(polar3),

        status_bar: Style::new().bg(polar1).fg(polar3),
        status_bar_key: Style::new().fg(frost1).add_modifier(Modifier::BOLD),

        popup_border: Style::new().fg(frost0),
        popup_title: Style::new().fg(frost0).add_modifier(Modifier::BOLD),

        log_info: Style::new().fg(snow0),
        log_error: Style::new().fg(aurora_red),
        log_success: Style::new().fg(aurora_green),

        spinner: Style::new().fg(frost0),
        filter_match: Style::new().fg(aurora_yellow).add_modifier(Modifier::BOLD),
    }
}

// ── TUI app config (persistence) ──────────────────────────

/// Path to the TUI's own config file
pub fn tui_config_path() -> Option<std::path::PathBuf> {
    dirs::config_dir().map(|p| p.join("yabridge-tui.toml"))
}

/// Load the saved theme preference from ~/.config/yabridge-tui.toml
pub fn load_theme_preference() -> Option<ThemeName> {
    let path = tui_config_path()?;
    let content = std::fs::read_to_string(path).ok()?;
    let table: toml::Table = toml::from_str(&content).ok()?;
    let name = table.get("theme")?.as_str()?;
    ThemeName::from_str(name)
}

/// Save the theme preference to ~/.config/yabridge-tui.toml
pub fn save_theme_preference(name: ThemeName) {
    let Some(path) = tui_config_path() else {
        return;
    };

    // Read existing config to preserve other keys
    let mut table: toml::Table = path
        .exists()
        .then(|| {
            std::fs::read_to_string(&path)
                .ok()
                .and_then(|c| toml::from_str(&c).ok())
        })
        .flatten()
        .unwrap_or_default();

    table.insert(
        "theme".to_string(),
        toml::Value::String(name.label().to_string()),
    );

    if let Ok(content) = toml::to_string_pretty(&table) {
        if let Some(parent) = path.parent() {
            let _ = std::fs::create_dir_all(parent);
        }
        let _ = std::fs::write(&path, content);
    }
}
