#include "arc/input/mouse.h"

#include "mouse.h"
#include "input.h"
#include "arc/math/point.h"
#include "arc/std/errno.h"
#include <stdlib.h>
#include <stdint.h>
#include <SDL_mouse.h>
#include <SDL_events.h>

void ARC_Mouse_CreateWithInput(ARC_Mouse **mouse, ARC_Input *input){
    *mouse = (ARC_Mouse *)malloc(sizeof(ARC_Mouse));
    (*mouse)->event   = input->event;
    (*mouse)->coords  = (ARC_Point *)malloc(sizeof(ARC_Point));
    (*mouse)->scrollY = (int32_t   *)malloc(sizeof(int32_t  ));
    (*mouse)->buttons = (ARC_MouseState *)malloc(sizeof(ARC_MouseState) * ARC_MOUSE_BUTTON_NUM);

    (*mouse)->buttonsReleased = (uint8_t *)malloc(sizeof(uint8_t));

    *(*mouse)->coords  = (ARC_Point){0, 0};
    *(*mouse)->scrollY = 0;

    for(uint8_t i = 0; i < ARC_MOUSE_BUTTON_NUM; i++){
        (*mouse)->buttons[i] = ARC_MOUSE_NONE;
    }

    *(*mouse)->buttonsReleased = 0;
}

void ARC_Mouse_Destroy(ARC_Mouse *mouse){
    free(mouse->buttonsReleased);

    free(mouse->buttons);
    free(mouse->scrollY);
    free(mouse->coords );

    free(mouse);
}

void ARC_Mouse_UpdateButton(ARC_Mouse *mouse, uint8_t button, uint32_t *buttons, uint32_t mask){
    if(*buttons & mask){
        mouse->buttons[button] = ARC_MOUSE_PRESSED;
        return;
    }
    
    if(mouse->buttons[button] == ARC_MOUSE_NONE){
        return;
    }

    if(mouse->buttons[button] == ARC_MOUSE_RELEASED){
        mouse->buttons[button] = ARC_MOUSE_NONE;
        --*mouse->buttonsReleased;
        return;
    }

    mouse->buttons[button] = ARC_MOUSE_RELEASED;
    ++*mouse->buttonsReleased;
}

void ARC_Mouse_Update(ARC_Mouse *mouse){
    *mouse->scrollY = 0;
    if(mouse->event->type == SDL_MOUSEWHEEL){
        *mouse->scrollY = mouse->event->wheel.y;
    }

    uint32_t buttons = SDL_GetMouseState(&(mouse->coords->x), &(mouse->coords->y));

    if(mouse->event->type != SDL_MOUSEBUTTONDOWN && mouse->event->type != SDL_MOUSEBUTTONUP){
        if(!*mouse->buttonsReleased){
            return;
        }

        for(uint8_t i = *mouse->buttonsReleased; i > 0; i--){
            if(mouse->buttons[i - 1] == ARC_MOUSE_RELEASED){
                mouse->buttons[i - 1] = ARC_MOUSE_NONE;
                --*mouse->buttonsReleased;
            }
        }

        // if(*mouse->buttonsReleased){
            // arc_errno = ARC_ERRNO_DATA;
            // ARC_DEBUG_LOG(arc_errno, "in ARC_Mouse_Update mouse->buttonsReleased == %u, it needs to be 0\n", *(mouse->buttonsReleased));
        // }
        return;
    }

    ARC_Mouse_UpdateButton(mouse, ARC_MOUSE_LEFT  , &buttons, SDL_BUTTON_LMASK );
    ARC_Mouse_UpdateButton(mouse, ARC_MOUSE_MIDDLE, &buttons, SDL_BUTTON_MMASK );
    ARC_Mouse_UpdateButton(mouse, ARC_MOUSE_RIGHT , &buttons, SDL_BUTTON_RMASK );
    ARC_Mouse_UpdateButton(mouse, ARC_MOUSE_X1    , &buttons, SDL_BUTTON_X1MASK);
    ARC_Mouse_UpdateButton(mouse, ARC_MOUSE_X2    , &buttons, SDL_BUTTON_X2MASK);
}

ARC_Point *ARC_Mouse_GetCoords(ARC_Mouse *mouse){
    return mouse->coords;
}

ARC_MouseState ARC_Mouse_GetState(ARC_Mouse *mouse, ARC_MouseButton button){
    return mouse->buttons[button];
}

int32_t *ARC_Mouse_GetScrollY(ARC_Mouse *mouse){
    return mouse->scrollY;
}