/*
 * devexplorer.h
 * Shared header for the MontaukOS Device Explorer
 * Copyright (c) 2026 Daniel Hammer
 */

#pragma once

#include <montauk/syscall.h>
#include <montauk/string.h>
#include <montauk/heap.h>
#include <gui/gui.hpp>
#include <gui/truetype.hpp>
#include <gui/mtk/widgets.hpp>

extern "C" {
#include <string.h>
#include <stdio.h>
}

using namespace gui;

// ============================================================================
// Constants
// ============================================================================

static constexpr int INIT_W       = 640;
static constexpr int INIT_H       = 460;
static constexpr int TOOLBAR_H    = 36;
static constexpr int CAT_H        = 28;
static constexpr int ITEM_H       = 24;
static constexpr int MAX_DEVS     = 64;
static constexpr int MAX_VIRTUAL_DEVS = 4;
static constexpr int MAX_TOTAL_DEVS   = MAX_DEVS + MAX_VIRTUAL_DEVS;
static constexpr int POLL_MS      = 2000;
static constexpr int INDENT       = 28;
static constexpr int FONT_SIZE    = 18;

enum DeviceCategory {
    CAT_CPU = 0,
    CAT_INTERRUPT,
    CAT_TIMER,
    CAT_INPUT,
    CAT_USB,
    CAT_NETWORK,
    CAT_DISPLAY,
    CAT_STORAGE,
    CAT_PCI,
    CAT_AUDIO,
    CAT_ACPI,
    CAT_PRINTER,
    NUM_CATEGORIES
};

static constexpr Color BG_COLOR       = Color::from_rgb(0xFF, 0xFF, 0xFF);
static constexpr Color TOOLBAR_BG     = Color::from_rgb(0xF5, 0xF5, 0xF5);
static constexpr Color BORDER_COLOR   = Color::from_rgb(0xCC, 0xCC, 0xCC);
static constexpr Color TEXT_COLOR     = Color::from_rgb(0x22, 0x22, 0x22);
static constexpr Color DIM_TEXT       = Color::from_rgb(0x66, 0x66, 0x66);
static constexpr Color WHITE          = Color::from_rgb(0xFF, 0xFF, 0xFF);
static constexpr Color ACCENT_COLOR   = Color::from_rgb(0x33, 0x66, 0xCC);

// ============================================================================
// Category data
// ============================================================================

static const char* category_names[] = {
    "CPU",
    "Interrupt",
    "Timer",
    "Input",
    "USB",
    "Network",
    "Display",
    "Storage",
    "PCI",
    "Audio",
    "ACPI",
    "Printers",
};

static const Color category_colors[] = {
    Color::from_rgb(0x33, 0x66, 0xCC),
    Color::from_rgb(0x88, 0x44, 0xAA),
    Color::from_rgb(0x22, 0x88, 0x22),
    Color::from_rgb(0xCC, 0x88, 0x00),
    Color::from_rgb(0x00, 0x88, 0x88),
    Color::from_rgb(0xCC, 0x55, 0x22),
    Color::from_rgb(0x44, 0x66, 0xCC),
    Color::from_rgb(0x99, 0x55, 0x00),
    Color::from_rgb(0x66, 0x66, 0x66),
    Color::from_rgb(0x8A, 0x5A, 0xCC),
    Color::from_rgb(0x55, 0x77, 0x88),
    Color::from_rgb(0x2F, 0x8B, 0x57),
};

// ============================================================================
// Display row model
// ============================================================================

enum RowType { ROW_CATEGORY, ROW_DEVICE };

struct DisplayRow {
    RowType type;
    int category;
    int dev_index;
};

static constexpr int MAX_DISPLAY_ROWS = MAX_TOTAL_DEVS + NUM_CATEGORIES;

// ============================================================================
// Scroll metrics (pixel-space) — shared by render and input handling so the
// draggable MTK scrollbar and the row layout stay in sync.
// ============================================================================

struct ScrollMetrics {
    int list_y;         // top of the scrollable list area
    int list_h;         // viewport height (view extent)
    int total_h;        // total content height (content extent)
    int max_scroll_px;  // maximum pixel scroll offset
    int scroll_px;      // current pixel scroll offset (clamped scroll_y)
};

// Bounds of the toolbar "Refresh" button — shared by render and hit-testing.
inline Rect refresh_button_rect() {
    constexpr int btn_w = 80, btn_h = 26;
    return { 8, (TOOLBAR_H - btn_h) / 2, btn_w, btn_h };
}

// ============================================================================
// Disk detail window
// ============================================================================

static constexpr int DD_TAB_COUNT = 2;
static const char* dd_tab_labels[DD_TAB_COUNT] = { "General", "Features" };

static constexpr int DD_INIT_W = 440;
static constexpr int DD_INIT_H = 420;
static constexpr int DD_TAB_BAR_H = 32;

struct DiskDetailState {
    montauk::abi::DiskInfo info;
    int active_tab;
    int win_id;
    int win_w, win_h;
    uint32_t* pixels;
    bool open;
};

// ============================================================================
// Main state
// ============================================================================

struct DevExplorerState {
    montauk::abi::DevInfo devs[MAX_TOTAL_DEVS];
    int dev_count;
    bool collapsed[NUM_CATEGORIES];
    int selected_row;
    int scroll_y;            // vertical scroll offset, in pixels (not rows)
    uint64_t last_poll_ms;

    int last_click_row;
    uint64_t last_click_ms;

    // Draggable MTK scrollbar interaction state
    int  mouse_x, mouse_y;   // last known pointer position (for hover)
    bool sb_hover;           // pointer is over the scrollbar track
    bool sb_dragging;        // thumb is being dragged
    int  sb_drag_offset;     // pointer offset from thumb top when drag began

    bool btn_hover;          // pointer is over the Refresh button

    DiskDetailState detail;
};

// ============================================================================
// Global state (extern — defined in main.cpp)
// ============================================================================

extern int g_win_w, g_win_h;
extern DevExplorerState g_state;
extern TrueTypeFont* g_font;
extern mtk::Theme g_theme;

// ============================================================================
// Function declarations — render.cpp
// ============================================================================

void render(uint32_t* pixels);

// ============================================================================
// Function declarations — main.cpp
// ============================================================================

int build_display_rows(DevExplorerState* de, DisplayRow* rows);
int append_printer_devices(montauk::abi::DevInfo* out, int max_count);
ScrollMetrics compute_scroll_metrics(DevExplorerState* de,
                                     const DisplayRow* rows, int row_count);
void set_scroll_from_px(DevExplorerState* de, const DisplayRow* rows,
                        int row_count, int target_px);

// ============================================================================
// Function declarations — diskdetail.cpp
// ============================================================================

void render_disk_detail();
void open_disk_detail(int port, const char* model);
void close_disk_detail();
bool handle_detail_mouse(int mx, int my, bool clicked);
