#include <stdint.h>
#include <stddef.h>
#include <neobbo.h>
#include <kprint.h>
#include <string.h>
#include <error.h>
#include <limine.h>
#include "../build/flanterm/src/flanterm.h"
#include "../build/flanterm/src/flanterm_backends/fb.h"
#include <arch/amd64/hal/gdt.h>
#include <arch/amd64/hal/idt.h>
#include <arch/amd64/hal/apic.h>
#include <arch/amd64/hal/timer.h>
#include <smp.h>
#include <arch/amd64/hal/tsc.h>
#include <mm/pmm.h>
#include <mm/slab.h>
#include <mm/vmm.h>
#include <mm/page.h>
#include <mm/kmalloc.h>
#include <sys/acpi.h>
#include <sys/pci.h>
#include <drivers/serial.h>
#include <drivers/pmt.h>
#include <drivers/ahci.h>
#include <scheduler/sched.h>
#include <sys/rand.h>
#include <sys/time.h>

static volatile struct limine_framebuffer_request framebuffer_request = {
    .id = LIMINE_FRAMEBUFFER_REQUEST_ID,
    .revision = 0,
};

struct flanterm_context *ft_ctx;

struct kernel_info kinfo;

void _start(void){

    /* initalize framebuffer */
    struct limine_framebuffer_response *fb_response = framebuffer_request.response;

    if(fb_response == NULL){
        goto death;
    }

    struct limine_framebuffer *fb = fb_response->framebuffers[0];

    if(fb == NULL){
        goto death;
    }

    ft_ctx = flanterm_fb_init(
            NULL,
            NULL,
            fb->address, fb->width, fb->height, fb->pitch,
            fb->red_mask_size, fb->red_mask_shift,
            fb->green_mask_size, fb->green_mask_shift,
            fb->blue_mask_size, fb->blue_mask_shift,
            NULL,
            NULL, NULL,
            NULL, NULL,
            NULL, NULL,
            NULL, 0, 0, 1,
            0, 0,
            0, 0
        );


    extern link_symbol_ptr text_start_addr, text_end_addr;
    
    set_gdt();
    set_idt();

    initialize_kinfo();

    kprintf("Welcome to Neobbo\n");

    klog("pmm", "Setting up the PMM");
    pmm_init();

    klog("vmm", "Setting up the page tables");
    vmm_init();

    init_page_array();

    _kmalloc_init();

    klog("smp", "Starting APs");
    smp_init();

    kprintf("the end!\n");

    death:
    for(;;){
         __builtin_ia32_pause();
    }
}

bool kernel_killed = false;
[[noreturn]] void kkill(void){
    kernel_killed = true;
    kprintf("The kernel has been killed.\n");
    
    #ifdef __x86_64__
        asm("cli");
        for(;;){
            __builtin_ia32_pause();
        }
    #else
        asm("hlt");
    #endif

}
