<script setup lang="ts">
import { computed, ref } from 'vue';
import InputText from 'primevue/inputtext';
import { usePrfStore } from '../stores';
import { OngekiButtons } from '../types';

const prf = usePrfStore();

const hasClickedM1Once = ref(false);

const handleKey = (
    button: string | undefined,
    event: KeyboardEvent,
    index?: number
) => {
    event.preventDefault();

    const keycode = toKeycode(event.code);
    if (keycode !== null && button !== undefined) {
        const data = prf.current!.data.keyboard!.data as any;
        if (index !== undefined) {
            data[button][index] = keycode;
        } else {
            data[button] = keycode;
        }
    }
};

const handleMouse = (
    button: string | undefined,
    event: MouseEvent,
    index?: number
) => {
    if (button === undefined || button == 'use_mouse') {
        return;
    }

    if (event.button === 0) {
        if (hasClickedM1Once.value === false) {
            hasClickedM1Once.value = true;
            return;
        }
    } else {
        event.preventDefault();
    }

    let keycode;
    switch (event.button) {
        case 0:
            keycode = 1;
            break;
        case 1:
            keycode = 4;
            break;
        case 2:
            keycode = 2;
            break;
        case 3:
            keycode = 5;
            break;
        case 4:
            keycode = 6;
            break;
        default:
            break;
    }
    if (keycode !== undefined) {
        const data = prf.current!.data.keyboard!.data as any;

        if (index !== undefined) {
            data[button][index] = keycode;
        } else {
            data[button] = keycode;
        }
    }
};

const getKey = (key: keyof OngekiButtons, index?: number) =>
    computed(() => {
        const data = prf.current!.data.keyboard?.data as any;
        const keycode =
            index === undefined
                ? (data[key] as number | undefined)
                : (data[key]?.[index] as number | undefined);
        return keycode && fromKeycode(keycode) ? fromKeycode(keycode) : '–';
    });

const KEY_MAP: { [key: number]: string } = {
    1: 'M1',
    2: 'M2',
    4: 'M3',
    5: 'M4',
    6: 'M5',
    8: 'Backspace',
    9: 'Tab',
    13: 'Enter',
    19: 'Pause',
    20: 'CapsLock',
    27: 'Escape',
    32: 'Space',
    33: 'PageUp',
    34: 'PageDown',
    35: 'End',
    36: 'Home',
    37: 'ArrowLeft',
    38: 'ArrowUp',
    39: 'ArrowRight',
    40: 'ArrowDown',
    45: 'Insert',
    46: 'Delete',
    48: 'Digit0',
    49: 'Digit1',
    50: 'Digit2',
    51: 'Digit3',
    52: 'Digit4',
    53: 'Digit5',
    54: 'Digit6',
    55: 'Digit7',
    56: 'Digit8',
    57: 'Digit9',
    65: 'KeyA',
    66: 'KeyB',
    67: 'KeyC',
    68: 'KeyD',
    69: 'KeyE',
    70: 'KeyF',
    71: 'KeyG',
    72: 'KeyH',
    73: 'KeyI',
    74: 'KeyJ',
    75: 'KeyK',
    76: 'KeyL',
    77: 'KeyM',
    78: 'KeyN',
    79: 'KeyO',
    80: 'KeyP',
    81: 'KeyQ',
    82: 'KeyR',
    83: 'KeyS',
    84: 'KeyT',
    85: 'KeyU',
    86: 'KeyV',
    87: 'KeyW',
    88: 'KeyX',
    89: 'KeyY',
    90: 'KeyZ',
    91: 'MetaLeft',
    92: 'MetaRight',
    93: 'ContextMenu',
    96: 'Numpad0',
    97: 'Numpad1',
    98: 'Numpad2',
    99: 'Numpad3',
    100: 'Numpad4',
    101: 'Numpad5',
    102: 'Numpad6',
    103: 'Numpad7',
    104: 'Numpad8',
    105: 'Numpad9',
    106: 'NumpadMultiply',
    107: 'NumpadAdd',
    109: 'NumpadSubtract',
    110: 'NumpadDecimal',
    111: 'NumpadDivide',
    112: 'F1',
    113: 'F2',
    114: 'F3',
    115: 'F4',
    116: 'F5',
    117: 'F6',
    118: 'F7',
    119: 'F8',
    120: 'F9',
    121: 'F10',
    122: 'F11',
    123: 'F12',
    144: 'NumLock',
    145: 'ScrollLock',
    160: 'ShiftLeft',
    161: 'ShiftRight',
    162: 'ControlLeft',
    163: 'ControlRight',
    164: 'AltLeft',
    165: 'AltRight',
    186: 'Semicolon',
    187: 'Equal',
    188: 'Comma',
    189: 'Minus',
    190: 'Period',
    191: 'Slash',
    192: 'Backquote',
    219: 'BracketLeft',
    220: 'Backslash',
    221: 'BracketRight',
    222: 'Quote',
};

const fromKeycode = (keyCode: number): string | null => {
    return KEY_MAP[keyCode] ?? null;
};

const toKeycode = (key: string): number | null => {
    const res = Object.entries(KEY_MAP).find(([_, v]) => v === key)?.[0];
    return res ? parseInt(res) : null;
};

defineProps({
    small: Boolean,
    verySmall: Boolean,
    tall: Boolean,
    tooltip: String,
    button: String,
    color: String,
    index: Number,
});
</script>

<template>
    <InputText
        :style="{
            width: small ? '3em' : '5em',
            height: small ? '3em' : tall ? '10em' : '5em',
            fontSize: small ? '0.9em' : '1em',
            backgroundColor: color,
        }"
        unstyled
        class="text-center buttoninputtext"
        v-tooltip="tooltip"
        @contextmenu.prevent="() => {}"
        @keydown="(ev: KeyboardEvent) => handleKey(button, ev, index)"
        @mousedown="
            (ev: MouseEvent) =>
                handleMouse(button as keyof OngekiButtons, ev, index)
        "
        @focusout="() => (hasClickedM1Once = false)"
        :model-value="getKey(button as keyof OngekiButtons, index) as any"
    />
</template>

<style scoped lang="css">
.buttoninputtext {
    border-radius: 6px;
    border: 1px solid rgba(200, 200, 200, 0.3);
}
</style>
