/*
 * Copyright (c) 2026, Chloe M.
 * Provided under the BSD-3 clause.
 *
 * Description:  Boot protocol abstraction layer
 * Author:       Chloe M.
 */

#include <ke/bpal.h>
#include <ex/trace.h>
#include <lib/limine.h>
#include <string.h>

#define FRAMEBUFFER FbResp->framebuffers[0]

#define DTRACE(Fmt, ...) \
    TRACE("[ BPAL ]: " Fmt, ##__VA_ARGS__)

/* Framebuffer request */
static struct limine_framebuffer_response *FbResp = NULL;
static struct limine_framebuffer_request FbReq = {
    .id = LIMINE_FRAMEBUFFER_REQUEST_ID,
    .revision = 0
};

/* HHDM request */
static struct limine_hhdm_response *HHDMResp = NULL;
static volatile struct limine_hhdm_request HHDMReq = {
    .id = LIMINE_HHDM_REQUEST_ID,
    .revision = 0
};

/* Bootloader information */
static struct limine_bootloader_info_response *LoaderInfoResp = NULL;
static volatile struct limine_bootloader_info_request LoaderInfoReq = {
    .id = LIMINE_BOOTLOADER_INFO_REQUEST_ID,
    .revision = 0
};

/* Bootloader perf information */
static struct limine_bootloader_performance_response *LoaderPerfResp = NULL;
static struct limine_bootloader_performance_request LoaderPerReq = {
    .id = LIMINE_BOOTLOADER_PERFORMANCE_REQUEST_ID,
    .revision = 0
};

/* Memory map request */
static struct limine_memmap_response *MapResp = NULL;
static volatile struct limine_memmap_request MapReq = {
    .id = LIMINE_MEMMAP_REQUEST_ID,
    .revision = 0
};

/* Module request */
static struct limine_module_response *ModResp = NULL;
static volatile struct limine_module_request ModReq = {
    .id = LIMINE_MODULE_REQUEST_ID,
    .revision = 0
};

/* Command line request */
static struct limine_executable_cmdline_response *CmdLineResp = NULL;
static struct limine_executable_cmdline_request CmdLineReq = {
    .id = LIMINE_EXECUTABLE_CMDLINE_REQUEST_ID,
    .revision = 0
};

/* RSDP request */
static struct limine_rsdp_response *RsdpResp = NULL;
static volatile struct limine_rsdp_request RsdpReq = {
    .id = LIMINE_RSDP_REQUEST_ID,
    .revision = 0
};

static ST_STATUS
LimineModuleLookup(CHAR *Path, BPAL_MODULE *Result)
{
    struct limine_file *Module;
    USIZE PathLen;

    if (Path == NULL || Result == NULL) {
        return STATUS_INVALID_PARAM;
    }

    if (ModResp == NULL) {
        return STATUS_NOT_FOUND;
    }

    PathLen = RtlStrLen(Path);
    for (USIZE Idx = 0; Idx < ModResp->module_count; ++Idx) {
        Module = ModResp->modules[Idx];
        if (*Module->path != *Path) {
            continue;
        }

        if (RtlMemCmp(Module->path, Path, PathLen) == 0) {
            Result->Data = Module->address;
            Result->Length = Module->size;
            return STATUS_SUCCESS;
        }
    }

    return STATUS_NOT_FOUND;
}

VOID
BpalInitFramebuffer(BPAL_HANDLE *Handle)
{
    BPAL_FRAMEBUFFER *Framebuffer;

    if (Handle == NULL) {
        return;
    }

    Framebuffer = &Handle->Framebuffer;
    Framebuffer->Address = FRAMEBUFFER->address;
    Framebuffer->Width = FRAMEBUFFER->width;
    Framebuffer->Height = FRAMEBUFFER->height;
    Framebuffer->Pitch = FRAMEBUFFER->pitch;
    Framebuffer->RedMaskSize = FRAMEBUFFER->red_mask_size;
    Framebuffer->RedMaskShift = FRAMEBUFFER->red_mask_shift;
    Framebuffer->GreenMaskSize = FRAMEBUFFER->green_mask_size;
    Framebuffer->GreenMaskShift = FRAMEBUFFER->green_mask_shift;
    Framebuffer->BlueMaskSize = FRAMEBUFFER->blue_mask_size;
    Framebuffer->BlueMaskShift = FRAMEBUFFER->blue_mask_shift;
}

static ST_STATUS
LimineMemEntryIdx(USIZE Idx, MEMMAP_ENTRY *Result)
{
    struct limine_memmap_entry *Entry;

    if (Idx >= MapResp->entry_count) {
        return STATUS_NOT_FOUND;
    }

    Entry = MapResp->entries[Idx];
    Result->Base = Entry->base;
    Result->Length = Entry->length;
    Result->Type = Entry->type;
    return STATUS_SUCCESS;
}

VOID
KeBpalLimineInit(BPAL_HANDLE *Handle)
{
    LoaderInfoResp = LoaderInfoReq.response;
    LoaderPerfResp = LoaderPerReq.response;
    HHDMResp = HHDMReq.response;
    ModResp = ModReq.response;
    FbResp = FbReq.response;
    MapResp = MapReq.response;
    CmdLineResp = CmdLineReq.response;
    RsdpResp = RsdpReq.response;

    DTRACE(
        "slut handed control by %s %s\n",
        LoaderInfoResp->name,
        LoaderInfoResp->version
    );

    DTRACE(
        "loader took %d usec\n",
        LoaderPerfResp->init_usec
    );

    DTRACE(
        "handoff took %d usec\n",
        LoaderPerfResp->exec_usec
    );

    Handle->CommandLine = CmdLineResp->cmdline;
    DTRACE(
        "kernel parameters : %s\n",
        Handle->CommandLine
    );

    BpalInitFramebuffer(Handle);
    Handle->KernelBase = HHDMResp->offset;
    Handle->MemEntryIdx = LimineMemEntryIdx;
    Handle->ModuleLookup = LimineModuleLookup;
    Handle->RsdpBase = RsdpResp->address;
}
