/*
    * main.cpp
    * libdialogs entry point for shared modal dialogs
    * Copyright (c) 2026 Daniel Hammer
*/

#include <montauk/syscall.h>
#include <montauk/string.h>
#include <montauk/heap.h>
#include <gui/gui.hpp>
#include <gui/standalone.hpp>
#include <gui/font.hpp>
#include <gui/dialogs.hpp>

#include "main.hpp"
#include "filedialog.hpp"
#include "printdialog.hpp"
#include "messagebox.hpp"

using namespace gui;
namespace dlg = gui::dialogs;

AppState g_app = {};
static bool g_fonts_ready = false;

void dialog_finish(const char* status, const char* path, const char* job_id, const char* message,
                   const char* printer_uri, const char* printer_name, uint32_t copies) {
    gui::dialogs::safe_copy(g_app.result.status, sizeof(g_app.result.status), status);
    gui::dialogs::safe_copy(g_app.result.path, sizeof(g_app.result.path), path);
    gui::dialogs::safe_copy(g_app.result.job_id, sizeof(g_app.result.job_id), job_id);
    gui::dialogs::safe_copy(g_app.result.printer_uri, sizeof(g_app.result.printer_uri), printer_uri);
    gui::dialogs::safe_copy(g_app.result.printer_name, sizeof(g_app.result.printer_name), printer_name);
    g_app.result.copies = copies;
    gui::dialogs::safe_copy(g_app.result.message, sizeof(g_app.result.message), message);
    g_app.running = false;
}

void dialog_cancel(const char* message) {
    dialog_finish("cancel", "", "", message, "", "", 0);
}

void cleanup() {
    if (g_app.is_print) {
        printdialog::cleanup();
    } else if (g_app.is_message) {
        messagebox::cleanup();
    } else {
        filedialog::cleanup();
    }
    g_app.win.destroy();
}

static void set_error_result(dlg::Result* result, const char* message) {
    if (!result) return;
    dlg::reset_result(result);
    dlg::safe_copy(result->status, sizeof(result->status), "error");
    dlg::safe_copy(result->message, sizeof(result->message), message);
}

static bool ensure_fonts(dlg::Result* result) {
    if (g_fonts_ready) return true;
    if (!fonts::init()) {
        if (result)
            set_error_result(result, "failed to initialize dialog fonts");
        return false;
    }
    g_fonts_ready = true;
    return true;
}

extern "C" bool dialogs_run_request(const dlg::Request* request, dlg::Result* out_result) {
    if (!request || !out_result) return false;

    set_error_result(out_result, "dialog failed");

    if (!ensure_fonts(out_result)) return true;

    if (request->kind != dlg::REQUEST_KIND_FILE &&
        request->kind != dlg::REQUEST_KIND_PRINT) {
        set_error_result(out_result, "unsupported dialog request");
        return true;
    }

    g_app = AppState {};
    g_app.request = *request;
    g_app.running = true;
    dlg::reset_result(&g_app.result);

    g_app.is_print = g_app.request.kind == dlg::REQUEST_KIND_PRINT;

    int init_w = filedialog::FILE_INIT_W;
    int init_h = filedialog::FILE_INIT_H;
    if (g_app.is_print) {
        init_w = printdialog::PRINT_INIT_W;
        init_h = printdialog::PRINT_INIT_H;
    }

    const char* default_title = g_app.is_print ? "Print" : "Open";
    const char* title = g_app.request.title[0] ? g_app.request.title : default_title;

    if (g_app.is_print) printdialog::init(g_app.request);
    else filedialog::init(g_app.request);

    if (!g_app.win.create(title, init_w, init_h)) {
        cleanup();
        set_error_result(out_result, "failed to create dialog window");
        return true;
    }

    if (g_app.is_print) printdialog::draw();
    else filedialog::draw();
    g_app.win.present();

    while (g_app.running) {
        if (g_app.is_print) printdialog::draw();
        else filedialog::draw();
        g_app.win.present();

        Montauk::WinEvent ev;
        int rc = g_app.win.poll(&ev);
        if (rc < 0) {
            dialog_cancel("");
            break;
        }
        if (rc == 0) {
            montauk::sleep_ms(16);
            continue;
        }

        if (ev.type == 3) {
            dialog_cancel("");
            break;
        }

        if (ev.type == 2 || ev.type == 4) {
            continue;
        }

        if (ev.type == 1) {
            if (g_app.is_print) printdialog::handle_mouse(ev);
            else filedialog::handle_mouse(ev);
            continue;
        }

        if (ev.type == 0) {
            if (g_app.is_print) printdialog::handle_key(ev.key);
            else filedialog::handle_key(ev.key);
        }
    }

    cleanup();
    *out_result = g_app.result;
    return true;
}

extern "C" uint8_t dialogs_message_box(const char* title,
                                       const char* message,
                                       uint8_t buttons) {
    if (!ensure_fonts(nullptr))
        return dlg::MESSAGE_BOX_RESULT_NONE;

    g_app = AppState {};
    g_app.running = true;
    g_app.is_message = true;

    const char* window_title = title && title[0] ? title : "Message";
    messagebox::init(message ? message : "", buttons);

    int init_w = 0;
    int init_h = 0;
    messagebox::preferred_size(window_title, &init_w, &init_h);

    if (!g_app.win.create(window_title, init_w, init_h)) {
        cleanup();
        return dlg::MESSAGE_BOX_RESULT_NONE;
    }

    messagebox::draw();
    g_app.win.present();

    while (g_app.running) {
        messagebox::draw();
        g_app.win.present();

        Montauk::WinEvent ev;
        int rc = g_app.win.poll(&ev);
        if (rc < 0) {
            messagebox::dismiss();
            break;
        }
        if (rc == 0) {
            montauk::sleep_ms(16);
            continue;
        }

        if (ev.type == 3) {
            messagebox::dismiss();
            break;
        }
        if (ev.type == 2 || ev.type == 4) {
            continue;
        }
        if (ev.type == 1) {
            messagebox::handle_mouse(ev);
            continue;
        }
        if (ev.type == 0) {
            messagebox::handle_key(ev.key);
        }
    }

    uint8_t choice = messagebox::selected_choice();
    cleanup();
    return choice ? choice : (uint8_t)dlg::MESSAGE_BOX_RESULT_NONE;
}
