#include "idt.h"
#include "io.h"
#include "serial.h"
#include "timer.h"
#include "keyboard.h"
#include "mouse.h"

struct idt_entry idt[256];
struct idt_ptr idtp;

extern void* isr_table[]; // Убедись, что это массив указателей на isr0-isr31
extern void irq0(), irq1(), irq12(), idt_load();

extern void isr0();  extern void isr1();  extern void isr2();  extern void isr3();
extern void isr4();  extern void isr5();  extern void isr6();  extern void isr7();
extern void isr8();  extern void isr9();  extern void isr10(); extern void isr11();
extern void isr12(); extern void isr13(); extern void isr14(); extern void isr15();
extern void isr16(); extern void isr17(); extern void isr18(); extern void isr19();
extern void isr20(); extern void isr21(); extern void isr22(); extern void isr23();
extern void isr24(); extern void isr25(); extern void isr26(); extern void isr27();
extern void isr28(); extern void isr29(); extern void isr30(); extern void isr31();

void* isr_table[] = {
    isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7,
    isr8, isr9, isr10, isr11, isr12, isr13, isr14, isr15,
    isr16, isr17, isr18, isr19, isr20, isr21, isr22, isr23,
    isr24, isr25, isr26, isr27, isr28, isr29, isr30, isr31
};

void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) {
    idt[num].base_low = (base & 0xFFFF);
    idt[num].base_high = ((base >> 16) & 0xFFFF);
    idt[num].sel = sel;
    idt[num].always0 = 0;
    idt[num].flags = flags;
}

void idt_init(void) {
    idtp.limit = (sizeof(struct idt_entry) * 256) - 1;
    idtp.base = (uint32_t)&idt;

    for (int i = 0; i < 32; i++) 
        idt_set_gate(i, (uint32_t)isr_table[i], 0x08, 0x8E);

    idt_set_gate(32, (uint32_t)irq0, 0x08, 0x8E);
    idt_set_gate(33, (uint32_t)irq1, 0x08, 0x8E);
    idt_set_gate(44, (uint32_t)irq12, 0x08, 0x8E);

    idt_load();
}

void isr_handler(struct registers *regs) {
    kprint_serial("\n!!! EXCEPTION !!!\n");
    kprint_serial("  int_no=");
    kprint_serial_dec(regs->int_no);
    kprint_serial(" err_code=");
    kprint_serial_dec(regs->err_code);
    kprint_serial("\n  EIP=0x");
    kprint_serial_hex(regs->eip);
    kprint_serial(" CS=0x");
    kprint_serial_hex(regs->cs);
    kprint_serial(" EFLAGS=0x");
    kprint_serial_hex(regs->eflags);
    kprint_serial("\n  EAX=0x");
    kprint_serial_hex(regs->eax);
    kprint_serial(" EBX=0x");
    kprint_serial_hex(regs->ebx);
    kprint_serial(" ECX=0x");
    kprint_serial_hex(regs->ecx);
    kprint_serial(" EDX=0x");
    kprint_serial_hex(regs->edx);
    kprint_serial("\n  ESP=0x");
    kprint_serial_hex(regs->esp);
    kprint_serial(" EBP=0x");
    kprint_serial_hex(regs->ebp);
    kprint_serial(" ESI=0x");
    kprint_serial_hex(regs->esi);
    kprint_serial(" EDI=0x");
    kprint_serial_hex(regs->edi);
    kprint_serial("\n  CR2=0x");
    uint32_t cr2;
    __asm__ __volatile__("mov %%cr2, %0" : "=r"(cr2));
    kprint_serial_hex(cr2);
    kprint_serial("\nSystem Halted.\n");
    while(1) asm("hlt");
}

void irq_handler(struct registers *regs) {
    if (regs->int_no == 32) {
        timer_handler();
    } else if (regs->int_no == 33) {
        keyboard_handler();
    } else if (regs->int_no == 44) {
        mouse_handler();
    } else {
    }

    if (regs->int_no >= 40) outb(0xA0, 0x20); // Slave
    outb(0x20, 0x20);                        // Master
}
