//! Derive [`ThemeColors`] from a [`Palette`].

use super::*;
use super::palette::{Palette, Rgb, darken, mid, rgb, tint};

/// Build a complete [`ThemeColors`] from a [`Palette`].
pub fn build(p: &Palette) -> ThemeColors {
    let darker_bg = darken(p.bg, 0.15);

    ThemeColors {
        ui: UiColors {
            bg: rgb(p.bg),
            bg_rgb: p.bg,
            text_primary: rgb(p.fg),
            text_muted: rgb(p.fg_dim),
            text_dim: rgb(p.fg_muted),
            border: rgb(p.surface2),
            header: rgb(p.cyan),
            unfocused: rgb(p.fg_muted),
            accent: rgb(p.accent),
            surface: rgb(p.surface),
        },
        status: StatusColors {
            playing_bg: rgb(tint(p.bg, p.green, 0.25)),
            playing_fg: rgb(p.green),
            stopped_bg: rgb(tint(p.bg, p.red, 0.25)),
            stopped_fg: rgb(p.red),
            fill_on: rgb(p.green),
            fill_off: rgb(p.fg_muted),
            fill_bg: rgb(p.surface),
        },
        selection: SelectionColors {
            cursor_bg: rgb(p.accent),
            cursor_fg: rgb(p.bg),
            selected_bg: rgb(tint(p.bg, p.accent, 0.30)),
            selected_fg: rgb(p.accent),
            in_range_bg: rgb(tint(p.bg, p.accent, 0.20)),
            in_range_fg: rgb(p.fg),
            cursor: rgb(p.accent),
            selected: rgb(tint(p.bg, p.accent, 0.30)),
            in_range: rgb(tint(p.bg, p.accent, 0.20)),
        },
        tile: TileColors {
            playing_active_bg: rgb(tint(p.bg, p.orange, 0.35)),
            playing_active_fg: rgb(p.orange),
            playing_inactive_bg: rgb(tint(p.bg, p.yellow, 0.30)),
            playing_inactive_fg: rgb(p.yellow),
            active_bg: rgb(tint(p.bg, p.cyan, 0.25)),
            active_fg: rgb(p.cyan),
            content_bg: rgb(tint(p.bg, p.cyan, 0.30)),
            inactive_bg: rgb(p.surface),
            inactive_fg: rgb(p.fg_dim),
            active_selected_bg: rgb(tint(p.bg, p.accent, 0.35)),
            active_in_range_bg: rgb(tint(p.bg, p.accent, 0.22)),
            link_bright: p.link_bright,
            link_dim: p.link_dim,
        },
        header: HeaderColors {
            tempo_bg: rgb(tint(p.bg, p.tempo_color, 0.30)),
            tempo_fg: rgb(p.tempo_color),
            bank_bg: rgb(tint(p.bg, p.bank_color, 0.25)),
            bank_fg: rgb(p.bank_color),
            pattern_bg: rgb(tint(p.bg, p.pattern_color, 0.25)),
            pattern_fg: rgb(p.pattern_color),
            stats_bg: rgb(p.surface),
            stats_fg: rgb(p.fg_dim),
        },
        modal: ModalColors {
            border: rgb(p.cyan),
            border_accent: rgb(p.accent),
            border_warn: rgb(p.orange),
            border_dim: rgb(p.fg_muted),
            confirm: rgb(p.orange),
            rename: rgb(p.purple),
            input: rgb(p.cyan),
            editor: rgb(p.cyan),
            preview: rgb(p.fg_muted),
        },
        flash: FlashColors {
            error_bg: rgb(tint(p.bg, p.red, 0.30)),
            error_fg: rgb(p.red),
            success_bg: rgb(tint(p.bg, p.green, 0.25)),
            success_fg: rgb(p.green),
            info_bg: rgb(p.surface),
            info_fg: rgb(p.fg),
        },
        list: ListColors {
            playing_bg: rgb(tint(p.bg, p.green, 0.25)),
            playing_fg: rgb(p.green),
            staged_play_bg: rgb(tint(p.bg, p.purple, 0.30)),
            staged_play_fg: rgb(p.purple),
            staged_stop_bg: rgb(tint(p.bg, p.red, 0.30)),
            staged_stop_fg: rgb(p.red),
            edit_bg: rgb(tint(p.bg, p.cyan, 0.25)),
            edit_fg: rgb(p.cyan),
            hover_bg: rgb(p.surface2),
            hover_fg: rgb(p.fg),
            muted_bg: rgb(tint(p.bg, p.surface, 0.30)),
            muted_fg: rgb(p.fg_muted),
            soloed_bg: rgb(tint(p.bg, p.yellow, 0.30)),
            soloed_fg: rgb(p.yellow),
        },
        link_status: LinkStatusColors {
            disabled: rgb(p.red),
            connected: rgb(p.green),
            listening: rgb(p.yellow),
        },
        syntax: syntax_colors(p, darker_bg),
        table: TableColors {
            row_even: rgb(darker_bg),
            row_odd: rgb(p.bg),
        },
        values: ValuesColors {
            tempo: rgb(p.orange),
            value: rgb(p.fg_dim),
        },
        hint: HintColors {
            key: rgb(p.orange),
            text: rgb(p.fg_muted),
        },
        view_badge: ViewBadgeColors {
            bg: rgb(p.fg),
            fg: rgb(p.bg),
        },
        nav: NavColors {
            selected_bg: rgb(tint(p.bg, p.accent, 0.35)),
            selected_fg: rgb(p.fg),
            unselected_bg: rgb(p.surface),
            unselected_fg: rgb(p.fg_muted),
        },
        editor_widget: EditorWidgetColors {
            cursor_bg: rgb(p.fg),
            cursor_fg: rgb(p.bg),
            selection_bg: rgb(tint(p.bg, p.accent, 0.30)),
            completion_bg: rgb(p.surface),
            completion_fg: rgb(p.fg),
            completion_selected: rgb(p.orange),
            completion_example: rgb(p.cyan),
        },
        browser: BrowserColors {
            directory: rgb(p.blue),
            project_file: rgb(p.purple),
            selected: rgb(p.orange),
            file: rgb(p.fg),
            focused_border: rgb(p.orange),
            unfocused_border: rgb(p.fg_muted),
            root: rgb(p.fg),
            file_icon: rgb(p.fg_muted),
            folder_icon: rgb(p.blue),
            empty_text: rgb(p.fg_muted),
        },
        input: InputColors {
            text: rgb(p.cyan),
            cursor: rgb(p.fg),
            hint: rgb(p.fg_muted),
        },
        search: SearchColors {
            active: rgb(p.orange),
            inactive: rgb(p.fg_muted),
            match_bg: rgb(p.yellow),
            match_fg: rgb(p.bg),
        },
        markdown: MarkdownColors {
            h1: rgb(p.cyan),
            h2: rgb(p.orange),
            h3: rgb(p.purple),
            code: rgb(p.green),
            code_border: rgb(mid(p.surface2, p.fg_muted, 0.3)),
            link: rgb(p.accent),
            link_url: rgb(mid(p.fg_muted, p.fg_dim, 0.3)),
            quote: rgb(p.fg_muted),
            text: rgb(p.fg),
            list: rgb(p.fg),
        },
        engine: engine_colors(p),
        dict: dict_colors(p),
        title: TitleColors {
            big_title: rgb(p.title_accent),
            author: rgb(p.title_author),
            link: rgb(p.green),
            license: rgb(p.orange),
            prompt: rgb(mid(p.fg_dim, p.fg, 0.3)),
            subtitle: rgb(p.fg),
        },
        meter: MeterColors {
            low: rgb(p.green),
            mid: rgb(p.yellow),
            high: rgb(p.red),
            low_rgb: p.meter[0],
            mid_rgb: p.meter[1],
            high_rgb: p.meter[2],
        },
        sparkle: SparkleColors {
            colors: p.sparkle,
        },
        confirm: ConfirmColors {
            border: rgb(p.orange),
            button_selected_bg: rgb(p.orange),
            button_selected_fg: rgb(p.bg),
        },
    }
}

fn syntax_colors(p: &Palette, darker_bg: Rgb) -> SyntaxColors {
    let syn_bg = |accent: Rgb| -> Color { rgb(tint(p.bg, accent, 0.20)) };
    let interval_fg = mid(p.green, p.fg, 0.3);

    SyntaxColors {
        gap_bg: rgb(darker_bg),
        executed_bg: rgb(tint(p.bg, p.purple, 0.15)),
        selected_bg: rgb(tint(p.bg, p.orange, 0.30)),
        emit: (rgb(p.fg), syn_bg(p.accent)),
        number: (rgb(p.purple), syn_bg(p.purple)),
        string: (rgb(p.green), syn_bg(p.green)),
        comment: (rgb(p.fg_muted), rgb(darker_bg)),
        keyword: (rgb(p.accent), syn_bg(p.accent)),
        stack_op: (rgb(p.blue), syn_bg(p.blue)),
        operator: (rgb(p.red), syn_bg(p.red)),
        sound: (rgb(p.cyan), syn_bg(p.cyan)),
        param: (rgb(p.orange), syn_bg(p.orange)),
        context: (rgb(p.orange), syn_bg(p.orange)),
        note: (rgb(p.green), syn_bg(p.green)),
        interval: (rgb(interval_fg), syn_bg(p.green)),
        variable: (rgb(p.purple), syn_bg(p.purple)),
        vary: (rgb(p.yellow), syn_bg(p.yellow)),
        generator: (rgb(p.cyan), syn_bg(p.cyan)),
        user_defined: (rgb(p.secondary), syn_bg(p.secondary)),
        default: (rgb(p.fg_dim), rgb(darker_bg)),
    }
}

fn engine_colors(p: &Palette) -> EngineColors {
    let divider = mid(p.surface2, p.fg_muted, 0.2);
    let label = mid(p.fg_muted, p.fg, 0.4);

    EngineColors {
        header: rgb(p.cyan),
        header_focused: rgb(p.yellow),
        divider: rgb(divider),
        scroll_indicator: rgb(mid(divider, p.fg_muted, 0.3)),
        label: rgb(label),
        label_focused: rgb(mid(label, p.fg, 0.3)),
        label_dim: rgb(mid(p.fg_muted, label, 0.3)),
        value: rgb(mid(p.fg_dim, p.fg, 0.5)),
        focused: rgb(p.yellow),
        normal: rgb(p.fg),
        dim: rgb(mid(divider, p.fg_muted, 0.3)),
        path: rgb(label),
        border_magenta: rgb(p.purple),
        border_green: rgb(p.green),
        border_cyan: rgb(p.cyan),
        separator: rgb(divider),
        hint_active: rgb(mid(p.orange, p.yellow, 0.5)),
        hint_inactive: rgb(divider),
    }
}

fn dict_colors(p: &Palette) -> DictColors {
    let divider = mid(p.surface2, p.fg_muted, 0.2);
    let label = mid(p.fg_muted, p.fg, 0.4);

    DictColors {
        word_name: rgb(p.green),
        word_bg: rgb(tint(p.bg, p.cyan, 0.20)),
        alias: rgb(p.fg_muted),
        stack_sig: rgb(p.purple),
        description: rgb(p.fg),
        example: rgb(label),
        category_focused: rgb(p.yellow),
        category_selected: rgb(p.cyan),
        category_normal: rgb(p.fg),
        category_dimmed: rgb(mid(divider, p.fg_muted, 0.3)),
        border_focused: rgb(p.yellow),
        border_normal: rgb(divider),
        header_desc: rgb(mid(label, p.fg, 0.3)),
    }
}
