/*
 * theme.cpp
 * Palette, theme, layout, and scaling for the Wikipedia client
 * Copyright (c) 2026 Daniel Hammer
 */

#include "wikipedia.h"

// ============================================================================
// Palette / theme
// ============================================================================

ReaderPalette reader_palette() {
    return {
        WHITE,
        WHITE,
        Color::from_rgb(0xF5, 0xF5, 0xF5),
        colors::BORDER,
        colors::TEXT_COLOR,
        Color::from_rgb(0x22, 0x22, 0x22),
        Color::from_rgb(0x77, 0x77, 0x77),
        g_accent,
        mtk::darken(g_accent, 32),
        mtk::lighten(g_accent, 214),
        Color::from_rgb(0xD0, 0x3E, 0x3E),
        Color::from_rgb(0xDD, 0x44, 0x44),
        Color::from_rgb(0xCC, 0xCC, 0xCC),
        WHITE,
    };
}

TrueTypeFont* current_body_font() {
    return g_font ? g_font : g_body_fonts[(int)ReaderFontFace::SANS];
}

TrueTypeFont* current_heading_font() {
    return g_font_serif ? g_font_serif : current_body_font();
}

void apply_reader_preferences() {
    static const int body_adjust[READER_TEXT_SIZE_COUNT] = {-2, 0, 4};
    static const int title_adjust[READER_TEXT_SIZE_COUNT] = {-4, 0, 6};
    static const int section_adjust[READER_TEXT_SIZE_COUNT] = {-3, 0, 5};

    int font_index = (int)g_reader_font_face;
    g_font = g_body_fonts[font_index] ? g_body_fonts[font_index]
                                      : g_body_fonts[(int)ReaderFontFace::SANS];
    g_font_serif = g_heading_fonts[font_index] ? g_heading_fonts[font_index]
                                               : g_heading_fonts[(int)ReaderFontFace::SERIF];

    FONT_SIZE = g_base_font_size + body_adjust[(int)g_reader_text_size];
    TITLE_SIZE = g_base_title_size + title_adjust[(int)g_reader_text_size];
    SECTION_SIZE = g_base_section_size + section_adjust[(int)g_reader_text_size];
    if (current_body_font())
        g_line_h = current_body_font()->get_line_height(FONT_SIZE) + 4;
}

mtk::Theme wiki_theme() {
    ReaderPalette palette = reader_palette();
    mtk::Theme theme = mtk::make_theme(palette.accent);
    theme.window_bg = palette.page_bg;
    theme.surface = palette.control_bg;
    theme.surface_alt = palette.toolbar_bg;
    theme.surface_hover = mtk::mix(palette.toolbar_bg, palette.accent, 26);
    theme.border = palette.border;
    theme.text = palette.text;
    theme.text_muted = palette.muted;
    theme.text_subtle = palette.muted;
    theme.accent = palette.accent;
    theme.accent_hover = palette.accent_hover;
    theme.accent_soft = palette.accent_soft;
    theme.selection = palette.accent;
    theme.danger = palette.danger;
    theme.danger_hover = palette.danger_hover;
    theme.disabled_bg = palette.disabled_bg;
    theme.disabled_fg = palette.disabled_fg;
    return theme;
}

void apply_scale(int scale) {
    switch (scale) {
    case 0:
        g_base_font_size = 14;
        g_base_title_size = 26;
        g_base_section_size = 20;
        break;
    case 2:
        g_base_font_size = 22;
        g_base_title_size = 40;
        g_base_section_size = 30;
        break;
    default:
        g_base_font_size = 18;
        g_base_title_size = 32;
        g_base_section_size = 24;
        break;
    }
    apply_reader_preferences();
    update_toolbar_height();
    reload_display_icons();
}

// ============================================================================
// Toolbar metrics
// ============================================================================

int search_control_h() {
    return gui_clamp(g_base_font_size + 12, 24, 32);
}

int reader_button_h() {
    return gui_clamp(search_control_h() - 4, 20, 28);
}

int display_toggle_icon_size() {
    return gui_clamp(search_control_h() - 12, 14, 20);
}

int display_toggle_button_w() {
    return gui_max(search_control_h(), display_toggle_icon_size() + 12);
}

int search_row_y() {
    return 6;
}

int reader_row_y() {
    return search_row_y() + search_control_h() + 6;
}

void update_toolbar_height() {
    int h = search_row_y() + search_control_h() + 6;
    if (g_display_controls_open)
        h += reader_button_h() + 6;
    TOOLBAR_H = h;
}

void reload_display_icons() {
    if (g_display_icon.pixels) svg_free(g_display_icon);
    if (g_display_icon_active.pixels) svg_free(g_display_icon_active);

    int icon_size = display_toggle_icon_size();
    ReaderPalette palette = reader_palette();
    g_display_icon = svg_load(DISPLAY_ICON_PATH, icon_size, icon_size, palette.text);
    g_display_icon_active = svg_load(DISPLAY_ICON_PATH, icon_size, icon_size, WHITE);
}

// ============================================================================
// Layout helpers
// ============================================================================

static int segmented_button_w(const char* label, int min_w) {
    return gui_max(text_width(label) + 16, min_w);
}

static int button_group_width(const char* const* labels, int count, int min_w, int gap) {
    int w = 0;
    for (int i = 0; i < count; i++) {
        if (i > 0) w += gap;
        w += segmented_button_w(labels[i], min_w);
    }
    return w;
}

static void layout_button_group(Rect* out, int count,
                                const char* const* labels,
                                int min_w, int gap,
                                int* x, int y, int h) {
    for (int i = 0; i < count; i++) {
        int w = segmented_button_w(labels[i], min_w);
        out[i] = {*x, y, w, h};
        *x += w + gap;
    }
    *x -= gap;
}

ReaderToolbarLayout toolbar_layout() {
    ReaderToolbarLayout lo {};
    int pad = 8;
    int search_h = search_control_h();
    int reader_h = reader_button_h();
    int display_w = display_toggle_button_w();
    int search_btn_w = 104;

    lo.search_button = {g_win_w - pad - search_btn_w, search_row_y(), search_btn_w, search_h};
    lo.display_button = {lo.search_button.x - 8 - display_w, search_row_y(), display_w, search_h};
    int field_w = lo.display_button.x - pad - 8;
    if (field_w < 80) field_w = 80;
    lo.search_field = {pad, search_row_y(), field_w, search_h};

    if (!g_display_controls_open)
        return lo;

    int gap = 4;
    int group_gap = 18;
    int label_gap = 8;
    int size_w = button_group_width(g_text_size_labels, READER_TEXT_SIZE_COUNT, 36, gap);
    int font_w = button_group_width(g_font_face_labels, READER_FONT_FACE_COUNT, 54, gap);
    int text_label_w = text_width("Text");
    int font_label_w = text_width("Font");
    int available_w = g_win_w - pad * 2;
    int total_w = text_label_w + label_gap + size_w + group_gap +
                  font_label_w + label_gap + font_w;
    lo.show_labels = total_w <= available_w;
    if (!lo.show_labels) {
        total_w = size_w + group_gap + font_w;
        text_label_w = 0;
        font_label_w = 0;
    }

    int x = total_w < available_w ? (g_win_w - total_w) / 2 : pad;
    int y = reader_row_y();
    int label_y = y + (reader_h - system_font_height()) / 2;

    if (lo.show_labels) {
        lo.text_size_label = {x, label_y, text_label_w, system_font_height()};
        x += text_label_w + label_gap;
    }

    layout_button_group(lo.text_size_buttons, READER_TEXT_SIZE_COUNT, g_text_size_labels, 36, gap, &x, y, reader_h);
    x += group_gap;
    lo.sep_x = x - group_gap / 2;

    if (lo.show_labels) {
        lo.font_face_label = {x, label_y, font_label_w, system_font_height()};
        x += font_label_w + label_gap;
    }

    layout_button_group(lo.font_buttons, READER_FONT_FACE_COUNT, g_font_face_labels, 54, gap, &x, y, reader_h);
    return lo;
}

Rect content_rect() {
    int y = TOOLBAR_H + 1;
    return {0, y, g_win_w, gui_max(g_win_h - y, 0)};
}

Rect article_column_rect() {
    Rect content = content_rect();
    int available_w = gui_max(content.w - TEXT_PAD * 2 - SCROLLBAR_W - 12, 80);
    int column_w = gui_min(available_w, 700);
    int x = TEXT_PAD + gui_max((available_w - column_w) / 2, 0);
    return {x, content.y, column_w, content.h};
}

int document_top_pad() {
    return g_phase == AppPhase::WELCOME ? 24 : 8;
}

Rect document_column_rect() {
    Rect column = article_column_rect();
    if (g_phase == AppPhase::WELCOME) {
        int inset = gui_min(24, column.w / 12);
        if (column.w - inset * 2 >= 320) {
            column.x += inset;
            column.w -= inset * 2;
        }
    }
    return column;
}

Rect search_button_rect() { return toolbar_layout().search_button; }
Rect search_field_rect()  { return toolbar_layout().search_field; }

// ============================================================================
// Scrolling
// ============================================================================

int visible_line_count() {
    Rect content = content_rect();
    if (g_line_h <= 0) return 0;
    return content.h / g_line_h;
}

int max_scroll_lines() {
    return mtk::scrollbar_max_offset(g_line_count, visible_line_count());
}

bool document_scrollable() {
    return g_phase == AppPhase::WELCOME || g_phase == AppPhase::DONE;
}

void clamp_scroll() {
    g_scroll_y = gui_clamp(g_scroll_y, 0, max_scroll_lines());
}

bool mouse_in_rect(const Rect& rect) {
    return rect.contains(g_mouse_x, g_mouse_y);
}

Rect scrollbar_track_rect() {
    Rect content = content_rect();
    int visible = visible_line_count();
    if (visible <= 0 || g_line_count <= visible) return {0, 0, 0, 0};
    return mtk::scrollbar_track_rect(content);
}

Rect scrollbar_thumb_rect() {
    Rect track = scrollbar_track_rect();
    if (track.empty()) return {0, 0, 0, 0};

    int visible = visible_line_count();
    if (visible <= 0 || g_line_count <= visible) return {0, 0, 0, 0};

    return mtk::scrollbar_thumb_rect(track, g_line_count, visible, g_scroll_y);
}

void set_scroll_from_thumb_top(int thumb_top) {
    Rect track = scrollbar_track_rect();
    Rect thumb = scrollbar_thumb_rect();
    if (track.empty() || thumb.empty()) return;

    g_scroll_y = mtk::scrollbar_offset_from_thumb_top(track,
                                                      g_line_count,
                                                      visible_line_count(),
                                                      thumb.h,
                                                      thumb_top);
    clamp_scroll();
}
