use ratatui::style::Color;

use super::{Background, Theme, ThemeColors};

struct GraphThemePalette {
    nodes: [[u8; 3]; 8],
    chrome: [u8; 3],
    title: [u8; 3],
    text: [u8; 3],
    fg: [u8; 3],
    grid: [u8; 3],
    bg: [u8; 3],
}

impl GraphThemePalette {
    const fn rgb(c: [u8; 3]) -> Color {
        Color::Rgb(c[0], c[1], c[2])
    }

    fn build(&self, background: Background) -> ThemeColors {
        ThemeColors {
            node_colors: self.nodes.map(Self::rgb).to_vec(),
            edge_color: Self::rgb(self.chrome),
            border_color: Self::rgb(self.chrome),
            title_color: Self::rgb(self.title),
            label_color: Self::rgb(self.text),
            legend_text_color: Self::rgb(self.text),
            legend_border_color: Self::rgb(self.chrome),
            selected_indicator_color: Self::rgb(self.fg),
            grid_color: Self::rgb(self.grid),
            background_color: match background {
                Background::Transparent => None,
                Background::Solid => Some(Self::rgb(self.bg)),
            },
            status_bar_color: Self::rgb(self.chrome),
            minimap_border_color: Self::rgb(self.chrome),
            minimap_viewport_color: Self::rgb(self.fg),
            minimap_bg_color: Some(Self::rgb(self.bg)),
        }
    }
}

const PALETTES: [GraphThemePalette; 18] = [
    GraphThemePalette {
        nodes: [
            [122, 162, 247],
            [187, 154, 247],
            [125, 207, 255],
            [224, 175, 104],
            [158, 206, 106],
            [247, 118, 142],
            [148, 226, 213],
            [255, 158, 100],
        ],
        chrome: [86, 95, 137],
        title: [187, 154, 247],
        text: [203, 206, 215],
        fg: [255, 255, 255],
        grid: [56, 62, 95],
        bg: [26, 27, 38],
    },
    GraphThemePalette {
        nodes: [
            [137, 180, 250],
            [203, 166, 247],
            [116, 199, 236],
            [249, 226, 175],
            [166, 227, 161],
            [245, 189, 220],
            [242, 205, 205],
            [250, 179, 135],
        ],
        chrome: [108, 112, 134],
        title: [205, 214, 244],
        text: [205, 214, 244],
        fg: [205, 214, 244],
        grid: [49, 50, 68],
        bg: [30, 30, 46],
    },
    GraphThemePalette {
        nodes: [
            [97, 175, 239],
            [198, 120, 221],
            [86, 182, 194],
            [229, 192, 123],
            [152, 195, 121],
            [224, 108, 117],
            [224, 150, 108],
            [171, 178, 191],
        ],
        chrome: [92, 99, 112],
        title: [171, 178, 191],
        text: [171, 178, 191],
        fg: [220, 223, 228],
        grid: [56, 63, 76],
        bg: [40, 44, 52],
    },
    GraphThemePalette {
        nodes: [
            [184, 187, 38],
            [215, 153, 33],
            [204, 94, 74],
            [214, 93, 14],
            [104, 157, 106],
            [131, 165, 152],
            [146, 131, 116],
            [254, 128, 25],
        ],
        chrome: [102, 92, 84],
        title: [235, 219, 178],
        text: [235, 219, 178],
        fg: [251, 241, 199],
        grid: [60, 56, 54],
        bg: [40, 40, 40],
    },
    GraphThemePalette {
        nodes: [
            [139, 233, 253],
            [189, 147, 249],
            [139, 233, 253],
            [255, 184, 108],
            [80, 250, 123],
            [255, 121, 198],
            [255, 139, 127],
            [255, 255, 150],
        ],
        chrome: [98, 114, 164],
        title: [248, 248, 242],
        text: [248, 248, 242],
        fg: [255, 255, 255],
        grid: [68, 71, 90],
        bg: [40, 42, 54],
    },
    GraphThemePalette {
        nodes: [
            [136, 192, 208],
            [143, 188, 187],
            [163, 190, 140],
            [235, 219, 178],
            [214, 140, 140],
            [216, 170, 133],
            [200, 200, 200],
            [163, 190, 140],
        ],
        chrome: [108, 120, 140],
        title: [216, 222, 233],
        text: [216, 222, 233],
        fg: [236, 239, 244],
        grid: [59, 66, 82],
        bg: [46, 52, 64],
    },
    GraphThemePalette {
        nodes: [
            [180, 142, 173],
            [234, 154, 151],
            [156, 207, 216],
            [246, 193, 119],
            [155, 138, 221],
            [235, 111, 146],
            [159, 188, 198],
            [209, 193, 168],
        ],
        chrome: [102, 110, 129],
        title: [87, 82, 121],
        text: [87, 82, 121],
        fg: [87, 82, 121],
        grid: [57, 53, 82],
        bg: [40, 37, 61],
    },
    GraphThemePalette {
        nodes: [
            [255, 215, 89],
            [255, 143, 105],
            [129, 204, 165],
            [100, 200, 218],
            [150, 205, 255],
            [220, 150, 255],
            [255, 180, 120],
            [200, 230, 150],
        ],
        chrome: [95, 120, 102],
        title: [60, 76, 67],
        text: [60, 76, 67],
        fg: [60, 76, 67],
        grid: [40, 50, 45],
        bg: [30, 38, 34],
    },
    GraphThemePalette {
        nodes: [
            [147, 191, 254],
            [255, 158, 181],
            [203, 166, 247],
            [137, 180, 130],
            [247, 234, 168],
            [255, 173, 130],
            [125, 196, 228],
            [242, 205, 205],
        ],
        chrome: [95, 115, 135],
        title: [98, 114, 164],
        text: [98, 114, 164],
        fg: [98, 114, 164],
        grid: [34, 40, 62],
        bg: [26, 30, 48],
    },
    GraphThemePalette {
        nodes: [
            [181, 137, 0],
            [203, 75, 22],
            [220, 50, 47],
            [211, 54, 130],
            [108, 113, 196],
            [38, 139, 210],
            [42, 161, 152],
            [133, 153, 0],
        ],
        chrome: [147, 161, 161],
        title: [131, 148, 150],
        text: [131, 148, 150],
        fg: [253, 246, 227],
        grid: [0, 74, 94],
        bg: [0, 43, 54],
    },
    // Catppuccin Frappé (dark) — PALETTES[10]
    GraphThemePalette {
        nodes: [
            [202, 158, 230], // accent (mauve)
            [244, 184, 228], // tag (pink)
            [140, 170, 238], // folder (blue)
            [231, 130, 132], // heading (red)
            [166, 209, 137], // success (green)
            [234, 153, 156], // destructive (maroon)
            [153, 209, 219], // spare_a (sky)
            [239, 159, 118], // spare_b (peach)
        ],
        chrome: [115, 121, 148],
        title: [198, 208, 245],
        text: [198, 208, 245],
        fg: [181, 191, 226],
        grid: [65, 69, 89],
        bg: [48, 52, 70],
    },
    // Catppuccin Macchiato (dark) — PALETTES[11]
    GraphThemePalette {
        nodes: [
            [198, 160, 246], // accent (mauve)
            [245, 189, 230], // tag (pink)
            [138, 173, 244], // folder (blue)
            [237, 135, 150], // heading (red)
            [166, 218, 149], // success (green)
            [238, 153, 160], // destructive (maroon)
            [145, 215, 227], // spare_a (sky)
            [245, 169, 127], // spare_b (peach)
        ],
        chrome: [110, 115, 141],
        title: [202, 211, 245],
        text: [202, 211, 245],
        fg: [184, 192, 224],
        grid: [54, 58, 79],
        bg: [36, 39, 58],
    },
    // Rose Pine Moon (dark) — PALETTES[12]
    GraphThemePalette {
        nodes: [
            [196, 167, 231], // accent (iris)
            [235, 188, 186], // tag (rose)
            [62, 143, 176],  // folder (pine)
            [246, 193, 119], // heading (gold)
            [156, 207, 216], // success (foam)
            [235, 111, 146], // destructive (love)
            [110, 106, 134], // spare_a (muted)
            [235, 188, 186], // spare_b (rose)
        ],
        chrome: [96, 92, 116],
        title: [224, 222, 244],
        text: [224, 222, 244],
        fg: [224, 222, 244],
        grid: [42, 39, 63],
        bg: [35, 33, 54],
    },
    // Gruvbox Material (dark) — PALETTES[13]
    GraphThemePalette {
        nodes: [
            [215, 153, 33],  // accent (yellow)
            [211, 134, 155], // tag (purple)
            [125, 174, 163], // folder (blue)
            [234, 157, 52],  // heading (orange)
            [169, 182, 101], // success (green)
            [234, 105, 98],  // destructive (red)
            [137, 180, 130], // spare_a (aqua)
            [240, 235, 215], // spare_b (fg0)
        ],
        chrome: [108, 100, 96],
        title: [235, 219, 178],
        text: [235, 219, 178],
        fg: [251, 241, 199],
        grid: [50, 48, 47],
        bg: [40, 40, 40],
    },
    // GitHub Dark — PALETTES[14]
    GraphThemePalette {
        nodes: [
            [88, 166, 255],  // accent (blue)
            [188, 140, 255], // tag (purple)
            [63, 185, 80],   // folder (green)
            [210, 153, 34],  // heading (yellow)
            [255, 123, 114], // success (orange)
            [248, 81, 73],   // destructive (red)
            [57, 210, 190],  // spare_a (teal)
            [139, 148, 158], // spare_b (fg muted)
        ],
        chrome: [100, 108, 120],
        title: [201, 209, 217],
        text: [201, 209, 217],
        fg: [255, 255, 255],
        grid: [33, 38, 45],
        bg: [13, 17, 23],
    },
    // Ayu Mirage (dark) — PALETTES[15]
    GraphThemePalette {
        nodes: [
            [255, 204, 102], // accent
            [255, 167, 89],  // tag (orange)
            [115, 184, 255], // folder (blue)
            [247, 135, 121], // heading (red)
            [135, 201, 105], // success (green)
            [255, 167, 89],  // destructive (orange)
            [57, 191, 204],  // spare_a (cyan)
            [193, 202, 214], // spare_b (fg)
        ],
        chrome: [100, 110, 125],
        title: [203, 204, 198],
        text: [203, 204, 198],
        fg: [255, 255, 255],
        grid: [40, 47, 62],
        bg: [31, 36, 48],
    },
    // Synthwave '84 (dark) — PALETTES[16]
    GraphThemePalette {
        nodes: [
            [255, 126, 219], // accent (pink)
            [54, 249, 242],  // tag (cyan)
            [123, 130, 149], // folder (comment)
            [255, 123, 114], // heading (orange-red)
            [114, 241, 184], // success (green)
            [254, 68, 68],   // destructive (red)
            [253, 226, 143], // spare_a (yellow)
            [152, 154, 206], // spare_b (purple-blue)
        ],
        chrome: [108, 103, 131],
        title: [248, 248, 242],
        text: [248, 248, 242],
        fg: [255, 255, 255],
        grid: [38, 33, 53],
        bg: [36, 29, 53],
    },
    // Material Theme (Darker) — PALETTES[17]
    GraphThemePalette {
        nodes: [
            [130, 170, 255], // accent (blue)
            [199, 146, 234], // tag (purple)
            [255, 203, 107], // folder (yellow)
            [247, 140, 108], // heading (orange)
            [195, 232, 141], // success (green)
            [240, 113, 120], // destructive (red)
            [137, 221, 255], // spare_a (cyan)
            [255, 139, 174], // spare_b (pink)
        ],
        chrome: [80, 80, 80],
        title: [238, 255, 255],
        text: [238, 255, 255],
        fg: [255, 255, 255],
        grid: [40, 40, 40],
        bg: [28, 28, 28],
    },
];

fn default_theme_colors(background: Background) -> ThemeColors {
    let gray = Color::Gray;
    let dark_gray = Color::DarkGray;
    let reset = Color::Reset;
    let white = Color::White;
    ThemeColors {
        node_colors: vec![
            Color::Cyan,
            Color::Magenta,
            Color::Blue,
            Color::Yellow,
            Color::Green,
            Color::Red,
            Color::LightCyan,
            Color::LightMagenta,
        ],
        edge_color: dark_gray,
        border_color: dark_gray,
        title_color: gray,
        label_color: gray,
        legend_text_color: gray,
        legend_border_color: dark_gray,
        selected_indicator_color: reset,
        grid_color: dark_gray,
        background_color: match background {
            Background::Transparent => None,
            Background::Solid => Some(Color::Black),
        },
        status_bar_color: dark_gray,
        minimap_border_color: dark_gray,
        minimap_viewport_color: white,
        minimap_bg_color: Some(Color::Black),
    }
}

pub fn theme_colors(theme: &Theme, background: Background) -> ThemeColors {
    match theme {
        Theme::Default => default_theme_colors(background),
        Theme::TokyoNight => PALETTES[0].build(background),
        Theme::CatppuccinMocha => PALETTES[1].build(background),
        Theme::Onedark => PALETTES[2].build(background),
        Theme::Gruvbox => PALETTES[3].build(background),
        Theme::Dracula => PALETTES[4].build(background),
        Theme::Nord => PALETTES[5].build(background),
        Theme::RosePine => PALETTES[6].build(background),
        Theme::Everforest => PALETTES[7].build(background),
        Theme::Kanagawa => PALETTES[8].build(background),
        Theme::Solarized => PALETTES[9].build(background),
        Theme::CatppuccinFrappe => PALETTES[10].build(background),
        Theme::CatppuccinMacchiato => PALETTES[11].build(background),
        Theme::RosePineMoon => PALETTES[12].build(background),
        Theme::GruvboxMaterial => PALETTES[13].build(background),
        Theme::GithubDark => PALETTES[14].build(background),
        Theme::AyuMirage => PALETTES[15].build(background),
        Theme::Synthwave => PALETTES[16].build(background),
        Theme::Material => PALETTES[17].build(background),
    }
}

/// Build [`ThemeColors`] from a custom theme's graph palette section.
///
/// Mirrors `GraphThemePalette::build()`. Missing or invalid hex values fall back
/// to `Color::Reset` (or `Color::Cyan` for the first node color).
pub fn custom_theme_colors(g: &crate::config::CustomGraph, background: Background) -> ThemeColors {
    let parse = |s: &str| crate::config::parse_hex_color(s).unwrap_or(Color::Reset);

    // Node colors: parse up to 8, pad with first-parsed or Cyan, truncate at 8.
    let parsed: Vec<Color> = g
        .nodes
        .iter()
        .filter_map(|h| crate::config::parse_hex_color(h))
        .collect();
    let default_node = parsed.first().copied().unwrap_or(Color::Cyan);
    let node_colors: Vec<Color> = if parsed.len() >= 8 {
        parsed[..8].to_vec()
    } else {
        let mut v = parsed;
        v.resize(8, default_node);
        v
    };

    let chrome = parse(&g.chrome);
    let title = parse(&g.title);
    let text = parse(&g.text);
    let fg = parse(&g.fg);
    let grid = parse(&g.grid);
    let bg_color =
        g.bg.as_ref()
            .and_then(|h| crate::config::parse_hex_color(h));

    ThemeColors {
        node_colors,
        edge_color: chrome,
        border_color: chrome,
        title_color: title,
        label_color: text,
        legend_text_color: text,
        legend_border_color: chrome,
        selected_indicator_color: fg,
        grid_color: grid,
        background_color: match background {
            Background::Transparent => None,
            Background::Solid => bg_color,
        },
        status_bar_color: chrome,
        minimap_border_color: chrome,
        minimap_viewport_color: fg,
        minimap_bg_color: bg_color.or(Some(Color::Black)),
    }
}
