#include "mouse.h"
#include "io.h"
#include "string.h"
#include "serial.h" // Для kprint_serial

#define PS2_DATA    0x60
#define PS2_STATUS  0x64
#define PS2_COMMAND 0x64

static void ps2_wait_write(void) {
    while (inb(PS2_STATUS) & 0x02);
}

static void ps2_wait_read(void) {
    while (!(inb(PS2_STATUS) & 0x01));
}

static void mouse_write(uint8_t data) {
    ps2_wait_write();
    outb(PS2_COMMAND, 0xD4); // Сигнал: шлем команду именно мыши
    ps2_wait_write();
    outb(PS2_DATA, data);
}

static uint8_t mouse_read(void) {
    ps2_wait_read();
    return inb(PS2_DATA);
}

void mouse_init(void) {
    uint8_t status;

    kprint_serial("Initializing PS/2 Mouse...\n");

    // Включаем второй порт PS/2 (мышь)
    ps2_wait_write();
    outb(PS2_COMMAND, 0xA8);
    io_wait();

    // Читаем Command Byte, чтобы включить прерывания
    ps2_wait_write();
    outb(PS2_COMMAND, 0x20);
    ps2_wait_read();
    status = inb(PS2_DATA) | 2; // Бит 1 — прерывания IRQ12 от мыши
    status &= ~0x20;            // Сбрасываем Бит 5 — активируем Mouse Clock

    // Записываем Command Byte обратно
    ps2_wait_write();
    outb(PS2_COMMAND, 0x60);
    ps2_wait_write();
    outb(PS2_DATA, status);

    // Настраиваем саму мышь
    mouse_write(0xF6); // Загрузить дефолтные параметры
    mouse_read();      // Читаем ACK (0xFA)

    mouse_write(0xF4); // Включаем передачу пакетов (Data Reporting)
    mouse_read();      // Читаем ACK (0xFA)

    kprint_serial("Mouse initialized successfully.\n");
}

static uint8_t mouse_cycle = 0;
static uint8_t mouse_packet[3];
volatile int mouse_x = 200;
volatile int mouse_y = 200;
volatile int left_click = 0;
volatile int right_click = 0;

void mouse_handler(void) {
    uint8_t status = inb(PS2_STATUS);
    
    // Проверяем, что в буфере реально есть данные и они от мыши (бит 5 выставлен)
    if (!(status & 0x01) || !(status & 0x20)) {
        return;
    }

    // ДЕБАГ: выводим каждый байт
    kprint_serial("M_BYTE: "); 
    kprint_serial_hex(status); 
    kprint_serial("\n");

    mouse_packet[mouse_cycle++] = inb(PS2_DATA);

    if (mouse_cycle == 3) {
        mouse_cycle = 0;

        // Бит 3 первого байта всегда должен быть равен 1 (проверка синхронизации)
        if (!(mouse_packet[0] & 0x08)) {
            return; 
        }

        uint8_t flags = mouse_packet[0];
        int offset_x = (int)mouse_packet[1];
        int offset_y = (int)mouse_packet[2];

        // Обработка знаков смещения (8 бит -> 32 бита с сохранением знака)
        if (flags & 0x10) offset_x |= 0xFFFFFF00;
        if (flags & 0x20) offset_y |= 0xFFFFFF00;

        mouse_x += offset_x;
        mouse_y -= offset_y; // Инвертируем Y, так как в VGA координатах 0 верх

		if (mouse_x < 0)  mouse_x = 0;
        if (mouse_x >= 1024) mouse_x = 1023;
        if (mouse_y < 0)  mouse_y = 0;
        if (mouse_y >= 768) mouse_y = 767;

        // Чек кнопок
        left_click  = flags & 0x01;
        right_click = flags & 0x02;

        // Выводим инфу в UART через itoa
        char buf[16];

        kprint_serial("Mouse: X=");
        itoa(mouse_x, buf, 10);
        kprint_serial(buf);

        kprint_serial(" Y=");
        itoa(mouse_y, buf, 10);
        kprint_serial(buf);

        if (left_click)  kprint_serial(" [LEFT]");
        if (right_click) kprint_serial(" [RIGHT]");

        kprint_serial("\n");
    }
}
