#include "dbg.h"
#include "arch.h"
#include "fb.h"
#include "printf.h"
#include "util.h"

#define BAR_H 18
#define HINT_H 18

static inline int bcd_to_bin(int bcd)
{
    return ((bcd >> 4) & 0xF) * 10 + (bcd & 0xF);
}

static int read_cmos(int reg)
{
    outb(0x70, (uint8_t)(reg | 0x80));
    return inb(0x71);
}

static void cmos_read_time(int *h, int *m, int *s)
{
    while(read_cmos(0x0A) & 0x80);
    *s = bcd_to_bin(read_cmos(0x00));
    *m = bcd_to_bin(read_cmos(0x02));
    *h = bcd_to_bin(read_cmos(0x04));
}

static void fill_rect(int x0, int y0, int x1, int y1, uint32_t color)
{
    uint32_t *ptr = (uint32_t*)(uintptr_t)fb.base;
    int stride = fb.pitch / 4;
    for(int y = y0; y < y1 && y < (int)fb.height; y++)
        for(int x = x0; x < x1 && x < (int)fb.width; x++)
            ptr[y * stride + x] = color;
}

static void draw_str(int x, int y, const char *s, uint32_t fg, uint32_t bg)
{
    for(int i = 0; s[i]; i++)
        fb_putchar_direct(x + i * 8, y, (unsigned char)s[i], fg, bg);
}

/* make_color() provided by fb.c via fb.h */

/* ── Top status bar ── */
static void render_top_bar(void)
{
    int w = (int)fb.width;
    uint32_t bar_bg = make_color(0x18, 0x18, 0x28);
    uint32_t fg_dim = make_color(0x66, 0x66, 0x88);
    uint32_t fg_bright = make_color(0xCC, 0xCC, 0xDD);
    uint32_t fg_accent = make_color(0x88, 0xCC, 0xFF);
    uint32_t fg_time = make_color(0xFF, 0xCC, 0x66);

    /* Fill bar background */
    fill_rect(0, 0, w, BAR_H, bar_bg);

    /* Left: "PrismOS" branding */
    draw_str(8, 1, "PrismOS", fg_accent, bar_bg);
    draw_str(8 + 7 * 8 + 4, 2, "v3", fg_dim, bar_bg);

    /* Center: time */
    int h, m, s;
    cmos_read_time(&h, &m, &s);
    char time_str[9];
    time_str[0] = '0' + (h / 10); time_str[1] = '0' + (h % 10);
    time_str[2] = ':';
    time_str[3] = '0' + (m / 10); time_str[4] = '0' + (m % 10);
    time_str[5] = ':';
    time_str[6] = '0' + (s / 10); time_str[7] = '0' + (s % 10);
    time_str[8] = 0;
    int tx = w / 2 - 4 * 8;
    draw_str(tx, 1, time_str, fg_time, bar_bg);

    /* Right: keyboard layout + debug indicator */
    extern int kbd_layout;
    const char *layout = kbd_layout ? "RU" : "EN";
    int rx = w - 8 * 8 - 4;
    draw_str(rx, 1, layout, fg_bright, bar_bg);

    /* Debug panel indicator */
    extern int panel_visible;
    if(panel_visible) {
        draw_str(rx - 3 * 8 - 8, 1, "DBG", make_color(0x44, 0xFF, 0x44), bar_bg);
    }

    /* Separator line */
    fill_rect(0, BAR_H - 1, w, BAR_H, make_color(0x33, 0x33, 0x55));
}

/* ── Bottom hint bar ── */
void dbg_render_hint(void)
{
    int w = (int)fb.width;
    int h = (int)fb.height;
    uint32_t bar_bg = make_color(0x18, 0x18, 0x28);
    uint32_t fg_dim = make_color(0x66, 0x66, 0x88);
    uint32_t fg_key = make_color(0xAA, 0xAA, 0xCC);

    int y0 = h - HINT_H;
    fill_rect(0, y0, w, h, bar_bg);
    fill_rect(0, y0, w, y0 + 1, make_color(0x33, 0x33, 0x55));

    /* Left: help hint */
    draw_str(8, y0 + 2, "F1", fg_key, bar_bg);
    draw_str(8 + 2 * 8 + 4, y0 + 2, "debug", fg_dim, bar_bg);

    draw_str(8 + 8 * 8 + 4, y0 + 2, "Alt+Shift", fg_key, bar_bg);
    draw_str(8 + 8 * 8 + 4 + 9 * 8 + 4, y0 + 2, "layout", fg_dim, bar_bg);

    /* Right: total lines in dbg */
    extern int dbg_total_lines;
    char cnt[16];
    int n = 0;
    int tmp = dbg_total_lines;
    if(tmp == 0) { cnt[n++] = '0'; }
    else {
        char rev[8];
        int rn = 0;
        while(tmp > 0) { rev[rn++] = '0' + (tmp % 10); tmp /= 10; }
        while(rn > 0) { cnt[n++] = rev[--rn]; }
    }
    cnt[n] = 0;
    int rx = w - (n + 5) * 8 - 4;
    draw_str(rx, y0 + 2, "log:", fg_dim, bar_bg);
    draw_str(rx + 4 * 8, y0 + 2, cnt, fg_key, bar_bg);
    draw_str(rx + (n + 4) * 8, y0 + 2, "lines", fg_dim, bar_bg);
}

/* ── Debug panel buffer ── */
#define DBG_COLS 50
#define DBG_ROWS 12
#define BORDER 2

static char buf[DBG_ROWS][DBG_COLS + 1];
static int col;
static int row;
static int dirty;
int panel_visible = 1;
int dbg_total_lines;

static void buf_putchar(char c)
{
    if(c == '\n' || col >= DBG_COLS) {
        col = 0;
        if(++row >= DBG_ROWS) {
            memmove(buf[0], buf[1], (DBG_ROWS - 1) * (DBG_COLS + 1));
            row = DBG_ROWS - 1;
            memset(buf[row], 0, DBG_COLS + 1);
        }
        dbg_total_lines++;
        dirty = 1;
        return;
    }
    if(c < 32) return;
    buf[row][col++] = c;
    dirty = 1;
}

void dbg_serial_hook(char c)
{
    buf_putchar(c);
}

static void serial_raw(char c)
{
    uint16_t port = 0x3F8;
    __asm__ volatile("outb %0, %1" : : "a"((uint8_t)c), "Nd"(port));
}

void dbg_putchar(char c)
{
    serial_raw(c);
    buf_putchar(c);
}

void dbg_puts(const char *s)
{
    while(*s) dbg_putchar(*s++);
}

void dbg_printf(const char *fmt, ...)
{
    char tmp[256];
    __builtin_va_list args;
    __builtin_va_start(args, fmt);
    vsnprintf(tmp, sizeof(tmp), fmt, args);
    __builtin_va_end(args);
    dbg_puts(tmp);
}

void dbg_init(void)
{
    col = 0;
    row = 0;
    dirty = 1;
    dbg_total_lines = 0;
}

int dbg_panel_visible(void)
{
    return panel_visible;
}

void dbg_toggle_panel(void)
{
    panel_visible = !panel_visible;
    dirty = 1;
    /* Force full screen redraw */
    fb_clear();
}

void dbg_clear_panel(void)
{
    memset(buf, 0, sizeof(buf));
    col = 0;
    row = 0;
    dirty = 1;
    dbg_total_lines = 0;
}

void dbg_render(void)
{
    render_top_bar();
    dbg_render_hint();

    if(!panel_visible) {
        dirty = 0;
        return;
    }

    if(!dirty) return;

    int panel_w = DBG_COLS * 8 + BORDER * 2;
    int panel_h = DBG_ROWS * 16 + BORDER * 2;
    int px = (int)fb.width - panel_w - 4;
    int py = (int)fb.height - panel_h - HINT_H - 4;
    if(px < 0) px = 0;
    if(py < 0) py = 0;

    uint32_t border_col = make_color(0x44, 0x44, 0x66);
    uint32_t title_bg = make_color(0x22, 0x22, 0x44);
    uint32_t bg_col = make_color(0x0C, 0x0C, 0x18);
    uint32_t fg_col = make_color(0x00, 0xDD, 0x44);
    uint32_t title_fg = make_color(0x88, 0x88, 0xAA);

    /* Border */
    fill_rect(px, py, px + panel_w, py + panel_h, border_col);

    /* Title bar (16px tall) */
    fill_rect(px + BORDER, py + BORDER,
              px + panel_w - BORDER, py + BORDER + 16, title_bg);
    draw_str(px + BORDER + 4, py + BORDER, "DEBUG", title_fg, title_bg);

    /* Separator under title */
    fill_rect(px + BORDER, py + BORDER + 16,
              px + panel_w - BORDER, py + BORDER + 17, make_color(0x44, 0x44, 0x66));

    /* Content area */
    fill_rect(px + BORDER, py + BORDER + 17,
              px + panel_w - BORDER, py + panel_h - BORDER, bg_col);

    for(int r = 0; r < DBG_ROWS; r++) {
        int ch_y = py + BORDER + 17 + r * 16;
        for(int c = 0; c < DBG_COLS; c++) {
            unsigned char ch = (unsigned char)buf[r][c];
            if(!ch) ch = ' ';
            fb_putchar_direct(px + BORDER + c * 8, ch_y, ch, fg_col, bg_col);
        }
    }

    dirty = 0;
}

void dbg_get_panel_rect(int *x, int *y, int *w, int *h)
{
    if(!panel_visible) {
        *x = 0; *y = 0; *w = 0; *h = 0;
        return;
    }
    int panel_w = DBG_COLS * 8 + BORDER * 2;
    int panel_h = DBG_ROWS * 16 + BORDER * 2;
    int px = (int)fb.width - panel_w - 4;
    int py = (int)fb.height - panel_h - HINT_H - 4;
    if(px < 0) px = 0;
    if(py < 0) py = 0;
    *x = px;
    *y = py;
    *w = panel_w;
    *h = panel_h;
}

void dbg_render_clock(void)
{
    static int last_sec = -1;
    int h, m, s;
    cmos_read_time(&h, &m, &s);
    if(s != last_sec) {
        last_sec = s;
        render_top_bar();
        dbg_render_hint();
    }
}
