/*
 * main.cpp
 * Entry point and event loop for the MontaukOS Wikipedia GUI client
 * Copyright (c) 2026 Daniel Hammer
 */

#include "wikipedia.h"

static TrueTypeFont* load_font(const char* path) {
    TrueTypeFont* f = (TrueTypeFont*)montauk::malloc(sizeof(TrueTypeFont));
    if (!f) return nullptr;
    montauk::memset(f, 0, sizeof(TrueTypeFont));
    if (!f->init(path)) { montauk::mfree(f); return nullptr; }
    return f;
}

static bool init_buffers_and_fonts() {
    g_lines       = (WikiLine*)montauk::malloc(MAX_LINES * sizeof(WikiLine));
    g_resp_buf    = (char*)malloc(RESP_MAX + 1);
    g_extract_buf = (char*)malloc(RESP_MAX + 1);
    if (!g_lines || !g_resp_buf || !g_extract_buf) return false;

    g_body_fonts[(int)ReaderFontFace::SANS] = load_font("0:/fonts/Roboto-Regular.ttf");
    if (!g_body_fonts[(int)ReaderFontFace::SANS])
        g_body_fonts[(int)ReaderFontFace::SANS] = load_font("0:/fonts/Roboto-Medium.ttf");
    g_heading_fonts[(int)ReaderFontFace::SANS] = load_font("0:/fonts/Roboto-Bold.ttf");

    g_body_fonts[(int)ReaderFontFace::SERIF] = load_font("0:/fonts/NotoSerif-Regular.ttf");
    g_heading_fonts[(int)ReaderFontFace::SERIF] = load_font("0:/fonts/NotoSerif-SemiBold.ttf");

    g_body_fonts[(int)ReaderFontFace::BOOK] = load_font("0:/fonts/C059-Roman.ttf");
    g_heading_fonts[(int)ReaderFontFace::BOOK] = load_font("0:/fonts/C059-Bold.ttf");

    if (!g_body_fonts[(int)ReaderFontFace::SANS]) return false;

    for (int i = 0; i < READER_FONT_FACE_COUNT; i++) {
        if (!g_heading_fonts[i]) g_heading_fonts[i] = g_body_fonts[i];
    }
    return true;
}

static void handle_key_event(const montauk::abi::WinEvent& ev, bool& search_pending) {
    uint8_t ascii = ev.key.ascii;
    uint8_t scan  = ev.key.scancode;

    if (g_search_focused) {
        if (ascii == '\n' || ascii == '\r') {
            search_pending = true;
        } else {
            mtk::text_input_key(g_query_input, g_query,
                                (int)sizeof(g_query), ev.key);
        }
        return;
    }

    if (!document_scrollable()) return;

    int visible = visible_line_count();
    int max_sc  = max_scroll_lines();
    if      (scan == 0x48) { if (g_scroll_y > 0) g_scroll_y--; }
    else if (scan == 0x50) { if (g_scroll_y < max_sc) g_scroll_y++; }
    else if (scan == 0x49) { g_scroll_y -= visible; if (g_scroll_y < 0) g_scroll_y = 0; }
    else if (scan == 0x51) { g_scroll_y += visible; if (g_scroll_y > max_sc) g_scroll_y = max_sc; }
    else if (scan == 0x47) { g_scroll_y = 0; }
    else if (scan == 0x4F) { g_scroll_y = max_sc; }
}

static void handle_mouse_event(const montauk::abi::WinEvent& ev, bool& search_pending) {
    int mx = ev.mouse.x, my = ev.mouse.y;
    g_mouse_x = mx;
    g_mouse_y = my;
    bool left_down = (ev.mouse.buttons & 1) != 0;
    bool just_clicked = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1);
    bool just_right_clicked = (ev.mouse.buttons & 2) && !(ev.mouse.prev_buttons & 2);
    bool just_released = !(ev.mouse.buttons & 1) && (ev.mouse.prev_buttons & 1);

    ReaderToolbarLayout lo = toolbar_layout();
    Rect scrollbar_track = scrollbar_track_rect();
    Rect scrollbar_thumb = scrollbar_thumb_rect();

    if (g_query_input.context.open || g_query_input.dragging) {
        int result = mtk::text_input_handle_mouse(g_query_input, lo.search_field,
                                                  g_query, (int)sizeof(g_query),
                                                  mx, my, ev.mouse.buttons,
                                                  ev.mouse.prev_buttons,
                                                  g_win_w, g_win_h,
                                                  g_search_focused);
        if (result & mtk::TEXT_INPUT_CONSUMED) {
            just_clicked = false;
            just_right_clicked = false;
        }
    }

    if (just_released) g_scroll_dragging = false;

    if (g_scroll_dragging && left_down)
        set_scroll_from_thumb_top(my - g_scroll_drag_offset);

    if (just_clicked || just_right_clicked) {
        if (lo.search_field.contains(mx, my)) {
            g_search_focused = true;
            mtk::text_input_handle_mouse(g_query_input, lo.search_field,
                                         g_query, (int)sizeof(g_query),
                                         mx, my, ev.mouse.buttons, ev.mouse.prev_buttons,
                                         g_win_w, g_win_h, true);
        } else if (scrollbar_thumb.contains(mx, my)) {
            g_search_focused = false;
            g_scroll_dragging = true;
            g_scroll_drag_offset = my - scrollbar_thumb.y;
        } else if (scrollbar_track.contains(mx, my)) {
            g_search_focused = false;
            g_scroll_dragging = true;
            g_scroll_drag_offset = scrollbar_thumb.h / 2;
            set_scroll_from_thumb_top(my - g_scroll_drag_offset);
        } else if (lo.display_button.contains(mx, my)) {
            g_search_focused = false;
            g_display_controls_open = !g_display_controls_open;
            update_toolbar_height();
            rebuild_current_document(true);
            clamp_scroll();
        } else if (handle_reader_option_click(mx, my)) {
            g_search_focused = false;
        } else {
            g_search_focused = false;
        }
    }

    if (just_clicked && lo.search_button.contains(mx, my) &&
        g_phase != AppPhase::LOADING) {
        search_pending = true;
    }

    if (ev.mouse.scroll != 0 && document_scrollable()) {
        g_scroll_y += ev.mouse.scroll * 3;
        clamp_scroll();
    }
}

extern "C" void _start() {
    if (!fonts::init())
        montauk::exit(1);

    if (!init_buffers_and_fonts())
        montauk::exit(1);

    g_accent = mtk::load_system_accent();
    apply_scale(montauk::win_getscale());
    build_welcome_lines(false);

    WsWindow win;
    if (!win.create("Wikipedia", INIT_W, INIT_H))
        montauk::exit(1);

    mtk::StandaloneHost host(&win);
    Canvas canvas = host.canvas();
    render(canvas);
    host.present();

    bool search_pending = false;
    bool welcome_fetch_pending = true;

    while (true) {
        if (welcome_fetch_pending) {
            welcome_fetch_pending = false;
            do_welcome_fetch();
            canvas = host.canvas();
            render(canvas);
            host.present();
            continue;
        }

        montauk::abi::WinEvent ev;
        int r = win.poll(&ev);

        if (r < 0) break;

        if (r == 0) {
            montauk::sleep_ms(16);
            canvas = host.canvas();
            render(canvas);
            host.present();
            continue;
        }

        if (ev.type == 3) break;  // close

        if (ev.type == 4) {
            apply_scale(win.scale_factor);
            g_scroll_dragging = false;
            rebuild_current_document(true);
        }

        if (ev.type == 2) {
            if (win.width > 0 && win.height > 0) {
                g_win_w = win.width;
                g_win_h = win.height;
                g_scroll_dragging = false;
                rebuild_current_document(true);
                clamp_scroll();
            }
        } else if (ev.type == 0 && ev.key.pressed) {
            handle_key_event(ev, search_pending);
        } else if (ev.type == 1) {
            handle_mouse_event(ev, search_pending);
        }

        if (search_pending && g_query[0] != '\0') {
            search_pending = false;
            if (is_main_page_query(g_query)) {
                g_phase = AppPhase::WELCOME;
                build_welcome_lines(false);
            } else {
                g_phase = AppPhase::LOADING;
                canvas = host.canvas();
                render(canvas);
                host.present();
                do_search(g_query);
            }
            clamp_scroll();
        }

        canvas = host.canvas();
        render(canvas);
        host.present();
    }

    if (g_display_icon.pixels) svg_free(g_display_icon);
    if (g_display_icon_active.pixels) svg_free(g_display_icon_active);
    win.destroy();
    montauk::exit(0);
}
