/*
 * render.cpp
 * MontaukOS Disk Tool - rendering
 * Copyright (c) 2026 Daniel Hammer
 */

#include "disks.h"
#include <gui/canvas.hpp>
#include <gui/mtk.hpp>

static mtk::Theme disks_theme() {
    mtk::Theme theme = mtk::make_theme();
    theme.window_bg = BG_COLOR;
    theme.surface = TOOLBAR_BG;
    theme.surface_alt = HEADER_BG;
    theme.surface_hover = HOVER_BG;
    theme.border = BORDER_COLOR;
    theme.text = TEXT_COLOR;
    theme.text_muted = FAINT_TEXT;
    theme.text_subtle = DIM_TEXT;
    theme.selection = HOVER_BG;
    theme.accent_soft = HOVER_BG;
    theme.disabled_bg = Color::from_rgb(0xF0, 0xF0, 0xF0);
    theme.disabled_fg = Color::from_rgb(0x9A, 0x9A, 0x9A);
    return theme;
}

static bool mouse_in_rect(const Rect& rect) {
    return rect.contains(g_state.mouse_x, g_state.mouse_y);
}

static mtk::WidgetState toolbar_button_state(const Rect& rect, bool enabled, bool active = false) {
    return mtk::widget_state(active, mouse_in_rect(rect), enabled);
}

static void draw_text_fit(Canvas& c, int x, int y,
                          const char* text, int max_w, Color color) {
    if (!text || !text[0] || max_w <= 4) return;
    if (text_width(text) <= max_w) {
        c.text(x, y, text, color);
        return;
    }

    const char* ellipsis = "...";
    int ell_w = text_width(ellipsis);
    if (ell_w >= max_w) return;

    char buf[96];
    int out = 0;
    while (text[out] && out < (int)sizeof(buf) - 4) {
        buf[out] = text[out];
        buf[out + 1] = '\0';
        if (text_width(buf) + ell_w > max_w)
            break;
        out++;
    }

    if (out <= 0) return;
    buf[out] = '.';
    buf[out + 1] = '.';
    buf[out + 2] = '.';
    buf[out + 3] = '\0';
    c.text(x, y, buf, color);
}

static int hovered_partition_row() {
    if (g_state.disk_count == 0 || g_state.selected_disk < 0) return -1;
    if (g_state.mouse_y < partition_list_y() || g_state.mouse_y >= g_win_h - STATUS_H) return -1;

    int part_indices[MAX_PARTS];
    int nparts = get_disk_parts(part_indices, MAX_PARTS);
    int row = (g_state.mouse_y - partition_list_y() + g_state.scroll_y) / ITEM_H;
    if (row < 0 || row >= nparts) return -1;
    return row;
}

static void draw_centered_text(Canvas& c, int width, int y, const char* text, Color color) {
    int tw = text_width(text);
    c.text((width - tw) / 2, y, text, color);
}

static void render_toolbar(Canvas& c, const mtk::Theme& theme) {
    auto& dt = g_state;
    int fh = system_font_height();

    c.fill_rect(0, 0, g_win_w, TOOLBAR_H, theme.surface);
    mtk::draw_separator(c, 0, TOOLBAR_H - 1, g_win_w, theme);

    for (int i = 0; i < dt.disk_count; i++) {
        Rect button = toolbar_disk_button_rect(i);
        char label[8];
        snprintf(label, sizeof(label), "Disk %d", i);
        mtk::draw_button(c, button, label, mtk::BUTTON_SECONDARY,
                         toolbar_button_state(button, true, i == dt.selected_disk), theme);
    }

    if (dt.disk_count == 0) {
        c.text(8, (TOOLBAR_H - fh) / 2, "No disks detected", theme.text);
        return;
    }

    bool has_sel = dt.selected_part >= 0;
    Rect newpart = toolbar_newpart_button_rect();
    Rect format = toolbar_format_button_rect();
    Rect mount = toolbar_mount_button_rect();
    Rect refresh = toolbar_refresh_button_rect();

    mtk::draw_button(c, newpart, "New Part", mtk::BUTTON_PRIMARY,
                     toolbar_button_state(newpart, true), theme);
    mtk::draw_button(c, format, "Format", mtk::BUTTON_TONAL,
                     toolbar_button_state(format, has_sel), theme);
    mtk::draw_button(c, mount, "Mount", mtk::BUTTON_TONAL,
                     toolbar_button_state(mount, has_sel), theme);
    mtk::draw_button(c, refresh, "Refresh", mtk::BUTTON_SECONDARY,
                     toolbar_button_state(refresh, true), theme);
}

static void render_content(Canvas& c, const mtk::Theme& theme) {
    auto& dt = g_state;
    int fh = system_font_height();

    if (dt.disk_count == 0 || dt.selected_disk < 0 || dt.selected_disk >= dt.disk_count)
        return;

    Montauk::DiskInfo& disk = dt.disks[dt.selected_disk];
    int y = content_title_y();

    char info_str[64];
    char size_str[24];
    format_disk_size(size_str, sizeof(size_str), disk.sectorCount, disk.sectorSizeLog);
    const char* dtype = disk.rpm == 1 ? "SSD" : "HDD";
    snprintf(info_str, sizeof(info_str), "%s  %s", size_str, dtype);

    int info_w = text_width(info_str);
    int info_x = g_win_w - info_w - MAP_PAD;
    int model_max_w = info_x - MAP_PAD - 12;
    draw_text_fit(c, MAP_PAD, y, disk.model, model_max_w, theme.text);
    c.text(info_x, y, info_str, theme.text_subtle);

    y = partition_map_y();

    Rect map_rect = {MAP_PAD, y, g_win_w - MAP_PAD * 2, MAP_H};
    c.fill_rounded_rect(map_rect.x, map_rect.y, map_rect.w, map_rect.h, theme.radius_md, theme.surface_alt);

    int part_indices[MAX_PARTS];
    int nparts = get_disk_parts(part_indices, MAX_PARTS);
    uint64_t total_sectors = disk.sectorCount;

    if (total_sectors > 0 && nparts > 0) {
        for (int pi = 0; pi < nparts; pi++) {
            Montauk::PartInfo& p = dt.parts[part_indices[pi]];
            int part_x = map_rect.x + (int)((p.startLba * (uint64_t)map_rect.w) / total_sectors);
            int part_w = (int)((p.sectorCount * (uint64_t)map_rect.w) / total_sectors);
            if (part_w < 2) part_w = 2;
            if (part_x + part_w > map_rect.x + map_rect.w)
                part_w = map_rect.x + map_rect.w - part_x;

            Color col = part_colors[pi % NUM_PART_COLORS];
            if (pi == dt.selected_part) {
                col = Color::from_rgb((col.r + 255) / 2,
                                      (col.g + 255) / 2,
                                      (col.b + 255) / 2);
            }
            c.fill_rounded_rect(part_x, map_rect.y + 2, part_w, MAP_H - 4, theme.radius_sm, col);

            char label[8];
            snprintf(label, sizeof(label), "%d", pi);
            int label_w = text_width(label);
            if (part_w > label_w + 4) {
                c.text(part_x + (part_w - label_w) / 2,
                       map_rect.y + (MAP_H - fh) / 2,
                       label, WHITE);
            }
        }
    }

    y = partition_header_y();
    c.fill_rect(0, y, g_win_w, HEADER_H, theme.surface_alt);
    mtk::draw_separator(c, 0, y + HEADER_H - 1, g_win_w, theme);

    int ty = y + (HEADER_H - fh) / 2;
    int col_idx  = 12;
    int col_name = 40;
    int col_type = g_win_w / 2 - 20;
    int col_size = g_win_w - 160;
    int col_lba  = g_win_w - 80;

    c.text(col_idx, ty, "#", theme.text_subtle);
    c.text(col_name, ty, "Name", theme.text_subtle);
    c.text(col_type, ty, "Type", theme.text_subtle);
    c.text(col_size, ty, "Size", theme.text_subtle);
    c.text(col_lba, ty, "LBA", theme.text_subtle);

    int list_y = partition_list_y();
    int list_bottom = g_win_h - STATUS_H;
    int hovered_row = hovered_partition_row();

    for (int pi = 0; pi < nparts; pi++) {
        int row_y = list_y + pi * ITEM_H - dt.scroll_y;
        if (row_y + ITEM_H <= list_y) continue;
        if (row_y >= list_bottom) break;

        Rect row_rect = {0, row_y, g_win_w, ITEM_H};
        if (pi == dt.selected_part) {
            mtk::draw_list_row(c, row_rect, true, false, theme);
        } else if (pi == hovered_row) {
            c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h, theme.surface_hover);
        } else {
            mtk::draw_list_row(c, row_rect, false, (pi & 1) != 0, theme);
        }

        Montauk::PartInfo& p = dt.parts[part_indices[pi]];

        c.fill_rounded_rect(col_idx, row_y + (ITEM_H - 10) / 2, 10, 10, 5,
                            part_colors[pi % NUM_PART_COLORS]);

        int ry = row_y + (ITEM_H - fh) / 2;
        draw_text_fit(c, col_name, ry, p.name[0] ? p.name : "(unnamed)",
                      col_type - col_name - 10, theme.text);
        draw_text_fit(c, col_type, ry, p.typeName,
                      col_size - col_type - 10, theme.text_subtle);

        char sz[24];
        format_disk_size(sz, sizeof(sz), p.sectorCount, disk.sectorSizeLog);
        c.text(col_size, ry, sz, theme.text);

        char lba_str[24];
        snprintf(lba_str, sizeof(lba_str), "%lu", (unsigned)p.startLba);
        c.text(col_lba, ry, lba_str, theme.text_muted);
    }

    if (nparts == 0)
        c.text(col_name, list_y + 8, "No partitions found", theme.text_muted);
}

static void render_status(Canvas& c, const mtk::Theme& theme) {
    auto& dt = g_state;
    int fh = system_font_height();

    int sy = g_win_h - STATUS_H;
    c.fill_rect(0, sy, g_win_w, STATUS_H, theme.surface_alt);
    mtk::draw_separator(c, 0, sy, g_win_w, theme);

    if (dt.status[0]) {
        uint64_t age = montauk::get_milliseconds() - dt.status_time;
        Color color = age < 5000 ? theme.text : theme.text_muted;
        c.text(8, sy + (STATUS_H - fh) / 2, dt.status, color);
    }
}

void render_format_window() {
    auto& dlg = g_state.fmt_dlg;
    if (!dlg.open || !dlg.pixels) return;

    Canvas c(dlg.pixels, FMT_DLG_W, FMT_DLG_H);
    mtk::Theme theme = disks_theme();
    c.fill(theme.window_bg);

    int fh = system_font_height();
    draw_centered_text(c, FMT_DLG_W, 12, "Format Partition", theme.text);
    draw_centered_text(c, FMT_DLG_W, 12 + fh + 6, dlg.part_desc, theme.text_subtle);

    int label_y = 12 + fh * 2 + 18;
    c.text(16, label_y, "Filesystem", theme.text_muted);

    for (int i = 0; i < NUM_FS_TYPES; i++) {
        Rect option = format_option_rect(FMT_DLG_W, i);
        if (i == dlg.selected_fs)
            c.fill_rounded_rect(option.x, option.y, option.w, option.h, theme.radius_md, theme.accent_soft);
        mtk::draw_radio(c, option, g_fsTypes[i].name, i == dlg.selected_fs, theme);
    }

    mtk::draw_modal_actions(c,
                            dialog_primary_button_rect(FMT_DLG_W, FMT_DLG_H), "Format",
                            mtk::BUTTON_DANGER,
                            mtk::widget_state(false, dlg.hover_format),
                            dialog_secondary_button_rect(FMT_DLG_W, FMT_DLG_H), "Cancel",
                            mtk::widget_state(false, dlg.hover_cancel),
                            theme);
}

void render_newpart_window() {
    auto& dlg = g_state.np_dlg;
    if (!dlg.open || !dlg.pixels) return;

    Canvas c(dlg.pixels, NP_DLG_W, NP_DLG_H);
    mtk::Theme theme = disks_theme();
    c.fill(theme.window_bg);

    int fh = system_font_height();
    const char* title = dlg.will_init_gpt ? "Initialize Disk" : "New Partition";
    draw_centered_text(c, NP_DLG_W, 12, title, theme.text);
    draw_centered_text(c, NP_DLG_W, 12 + fh + 6, dlg.disk_desc, theme.text_subtle);

    Color warn_color = dlg.will_init_gpt ? theme.danger : theme.text;
    int warn_y = 12 + fh * 2 + 20;
    draw_centered_text(c, NP_DLG_W, warn_y, dlg.warn_line1, warn_color);
    draw_centered_text(c, NP_DLG_W, warn_y + fh + 4, dlg.warn_line2, warn_color);

    const char* confirm_label = dlg.will_init_gpt ? "Initialize" : "Create";
    mtk::ButtonVariant confirm_variant = dlg.will_init_gpt ? mtk::BUTTON_DANGER : mtk::BUTTON_PRIMARY;
    mtk::draw_modal_actions(c,
                            dialog_primary_button_rect(NP_DLG_W, NP_DLG_H), confirm_label,
                            confirm_variant,
                            mtk::widget_state(false, dlg.hover_confirm),
                            dialog_secondary_button_rect(NP_DLG_W, NP_DLG_H), "Cancel",
                            mtk::widget_state(false, dlg.hover_cancel),
                            theme);
}

void render(uint32_t* pixels) {
    if (!pixels) return;

    Canvas c(pixels, g_win_w, g_win_h);
    mtk::Theme theme = disks_theme();
    c.fill(theme.window_bg);
    render_toolbar(c, theme);
    render_content(c, theme);
    render_status(c, theme);
}
