/*
    * table.hpp
    * Montauk Toolkit table/list helpers
    * Copyright (c) 2026 Daniel Hammer
*/

#pragma once

#include "gui/canvas.hpp"
#include "gui/mtk/theme.hpp"

namespace gui::mtk {

struct TableColumn {
    const char* label;
    int x;
    int w;
};

struct TableLayout {
    Rect header;
    Rect body;
    int row_h;
};

struct TableStyle {
    Color header_bg;
    Color header_border;
    Color header_text;
    Color row_selected_bg;
    Color row_hover_bg;
};

inline TableStyle make_table_style(const Theme& theme) {
    return {
        theme.surface_alt,
        theme.border,
        theme.text_subtle,
        theme.accent_soft,
        colors::TRANSPARENT,
    };
}

inline int table_visible_rows(const TableLayout& layout) {
    if (layout.row_h <= 0 || layout.body.h <= 0) return 0;
    return layout.body.h / layout.row_h;
}

inline int table_max_scroll(const TableLayout& layout, int row_count) {
    int visible = table_visible_rows(layout);
    if (row_count > visible && visible > 0) return row_count - visible;
    return 0;
}

inline void clamp_table_scroll(int* scroll, const TableLayout& layout, int row_count) {
    if (!scroll) return;
    *scroll = gui_clamp(*scroll, 0, table_max_scroll(layout, row_count));
}

inline void ensure_table_row_visible(int* scroll,
                                     const TableLayout& layout,
                                     int row_count,
                                     int selected) {
    if (!scroll || selected < 0) return;
    int visible = table_visible_rows(layout);
    if (visible <= 0) return;
    if (selected < *scroll) {
        *scroll = selected;
    } else if (selected >= *scroll + visible) {
        *scroll = selected - visible + 1;
    }
    clamp_table_scroll(scroll, layout, row_count);
}

inline Rect table_row_rect(const TableLayout& layout, int scroll, int row_index) {
    return {
        layout.body.x,
        layout.body.y + (row_index - scroll) * layout.row_h,
        layout.body.w,
        layout.row_h
    };
}

inline Rect table_cell_rect(const Rect& row_rect, const TableColumn& col) {
    return {row_rect.x + col.x, row_rect.y, col.w, row_rect.h};
}

inline int table_hit_row(const TableLayout& layout,
                         int scroll,
                         int row_count,
                         int mx,
                         int my) {
    if (!layout.body.contains(mx, my) || layout.row_h <= 0) return -1;
    int row = (my - layout.body.y) / layout.row_h;
    int index = scroll + row;
    if (index < 0 || index >= row_count) return -1;
    return index;
}

using TableRowRenderer = void (*)(Canvas& c,
                                  void* userdata,
                                  int row_index,
                                  const Rect& row_rect,
                                  int text_y,
                                  const TableColumn* cols,
                                  int col_count,
                                  const Theme& theme,
                                  const TableStyle& style);

inline void draw_table(Canvas& c,
                       const TableLayout& layout,
                       const TableColumn* cols,
                       int col_count,
                       int row_count,
                       int scroll,
                       int selected,
                       int hovered,
                       const Theme& theme,
                       const TableStyle& style,
                       TableRowRenderer draw_row,
                       void* userdata) {
    c.fill_rect(layout.header.x, layout.header.y, layout.header.w, layout.header.h, style.header_bg);
    c.hline(layout.header.x, layout.header.y + layout.header.h - 1, layout.header.w, style.header_border);

    int fh = system_font_height();
    int header_text_y = layout.header.y + (layout.header.h - fh) / 2;
    for (int i = 0; i < col_count; i++) {
        c.text(layout.header.x + cols[i].x, header_text_y, cols[i].label, style.header_text);
    }

    int visible = table_visible_rows(layout);
    for (int row = 0; row < visible; row++) {
        int index = scroll + row;
        if (index >= row_count) break;

        Rect row_rect = table_row_rect(layout, scroll, index);
        if (index == selected) {
            c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h, style.row_selected_bg);
        } else if (index == hovered && style.row_hover_bg.a > 0) {
            c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h, style.row_hover_bg);
        }

        if (draw_row) {
            int text_y = row_rect.y + (layout.row_h - fh) / 2;
            draw_row(c, userdata, index, row_rect, text_y, cols, col_count, theme, style);
        }
    }
}

} // namespace gui::mtk
