/*
 * Copyright (c) 2026, Chloe M.
 * Provided under the BSD-3 clause.
 *
 * Description: Bugcheck handler
 * Author:      Chloe M.
 */

#include <ex/trace.h>
#include <ke/bugcheck.h>
#include <drivers/bootvid/fbio.h>
#include <ptdef.h>

/* Used to safely obtain bugcheck reason */
#define BUGCHECK_REASON(REASON)         \
    ((REASON) >= NELEM(ReasonTable))    \
        ? "bad"                         \
        : ReasonTable[(REASON)]

/* Prints the bugcheck banner */
#define BUGCHECK_BANNER()                                                    \
    TRACE(                                                                   \
        "\033[31;40m! ***** \033[37;40mBUGCHECK \033[31;40m***** !\033[0m\n" \
    );

/* Globals to reduce stack usage */
static va_list Ap;
static CHAR BugCheckBuf[256];
static CHAR BugCheckMsg[] =
    "Something went wrong during system operation and the machine has\n"
    "been halted to prevent data loss.\n\n";

/* Table of reason strings */
static CHAR *ReasonTable[] = {
    [BUGCHECK_MISC] = "misc reason",
    [BUGCHECK_OOM]  = "out of memory",
    [BUGCHECK_IO_ERROR] = "i/o error",
    [BUGCHECK_UNBOUND_RESRC] = "unbounded resource",
    [BUGCHECK_EXCEPTION] = "fatal exception",
    [BUGCHECK_IRQL_NOT_GTE] = "irql not greater than or equal",
    [BUGCHECK_IRQL_NOT_LTE] = "irql not less than or equal",
    [BUGCHECK_BAD_FREE] = "bad free",
    [BUGCHECK_BAD_CHECKSUM] = "bad checksum",
    [BUGCHECK_MISSING_HARDWARE] = "missing hardware",
    [BUGCHECK_SYSTEMPROC_KILLED] = "critical system process killed"
};

VOID
KiBugCheck(BUGCHECK_REASON Reason, const CHAR *Fmt, ...)
{
    /* Enable the console if we don't have one */
    if (!BootVidConsEn()) {
        BootVidInitCons(NULL);
    }

    va_start(Ap, Fmt);
    VFmtPrintf(BugCheckBuf, sizeof(BugCheckBuf), Fmt, Ap);

    BUGCHECK_BANNER();
    TRACE("\033[37;40m");
    TRACE(BugCheckMsg);
    TRACE("\033[31;40mbugcheck: \033[37;40m%s", BugCheckBuf);
    TRACE("\033[31;40mreason: \033[37;40m%s\n", BUGCHECK_REASON(Reason));
    TRACE("\033[0m");
}
