#include <errno.h>
#include <luna/String.h>
#include <moon/Keyboard.h>
#include <moon/Mouse.h>
#include <os/File.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <unistd.h>

Result<void> process_mouse_packet(const moon::MousePacket& packet)
{
    bool right = packet.buttons & moon::MouseButton::Right;
    bool left = packet.buttons & moon::MouseButton::Left;
    bool middle = packet.buttons & moon::MouseButton::Middle;

    Vector<StringView> buttons;
    if (right) TRY(buttons.try_append("RIGHT"_sv));
    if (left) TRY(buttons.try_append("LEFT"_sv));
    if (middle) TRY(buttons.try_append("MIDDLE"_sv));

    String button_string;
    if (!buttons.size()) button_string = TRY(String::from_cstring("NONE"));
    else
        button_string = TRY(String::join(buttons, " | "_sv));

    os::println("Mouse packet: xdelta=%d, ydelta=%d, buttons=(%s)", packet.xdelta, packet.ydelta,
                button_string.chars());

    return {};
}

Result<int> luna_main(int, char**)
{
    auto mouse = TRY(os::File::open("/dev/mouse", os::File::ReadOnly));
    mouse->set_buffer(os::File::NotBuffered);

    auto keyboard = TRY(os::File::open("/dev/kbd", os::File::ReadOnly));
    keyboard->set_buffer(os::File::NotBuffered);

    ioctl(STDIN_FILENO, TTYSETGFX, 1);

    while (1)
    {
        struct pollfd fds[] = {
            { .fd = mouse->fd(), .events = POLLIN, .revents = 0 },
            { .fd = keyboard->fd(), .events = POLLIN, .revents = 0 },
        };

        int rc = poll(fds, 2, 1000);
        if (!rc) continue;
        if (rc < 0) { os::println("poll: error: %s", strerror(errno)); }

        if (fds[0].revents & POLLIN)
        {
            moon::MousePacket packet;
            TRY(mouse->read_typed(packet));
            TRY(process_mouse_packet(packet));
        }
        if (fds[1].revents & POLLIN)
        {
            moon::KeyboardPacket packet;
            TRY(keyboard->read_typed(packet));
            os::println("Keyboard packet: %s key %u", packet.released ? "released" : "pressed", packet.key);
        }
    }

    return 0;
}