import * as React from 'react';
import {HOME_BUTTON_IMAGE} from '/constants';
import {sendKeyDown} from '/packet';

export interface OverlayControlsProps {
    firstMenuElement: React.RefObject<HTMLAnchorElement>,
    setHiddenMenu: (c: boolean) => void,
    webSocket: WebSocket | null;
};

interface ControlMap {
    [id: string]: {key: number, ref: React.RefObject<HTMLAnchorElement>, sym: string, classes: string, transformX?: number, transformY?: number}
};

export default function OverlayControls({firstMenuElement, setHiddenMenu, webSocket}: OverlayControlsProps) {
    function showOverlayMenu() {
        setHiddenMenu(false);
        setTimeout(() => {
            if (firstMenuElement.current == null) {
                return;
            }
            firstMenuElement.current.focus();
        }, 100);
    }
    const [onGoingTouches, setOnGoingTouches] = React.useState<{[id: string]: number}>({});
    function mouseDown(e: React.MouseEvent<HTMLAnchorElement> | React.TouchEvent<HTMLAnchorElement>, key: number) {
        e.preventDefault();
        if (webSocket == null) {
            console.log('There is not websocket');
            return;
        }
        sendKeyDown(webSocket, true, key);
    }

    function mouseUp(e: React.MouseEvent<HTMLAnchorElement> | React.TouchEvent<HTMLAnchorElement>, key: number) {
        e.preventDefault();
        if (webSocket == null) {
            console.log('There is not websocket');
            return;
        }
        sendKeyDown(webSocket, false, key);
    }

    const controls: ControlMap = {};
    controls.a = {
        ref: React.useRef<HTMLAnchorElement|null>(null),
        key: 0,
        sym: 'A',
        classes: 'control-a control-button-a-b control control-button',
    };
    controls.b = {
        ref: React.useRef<HTMLAnchorElement|null>(null),
        key: 1,
        sym: 'B',
        transformX: 50,
        classes: 'control-b control-button-a-b control control-button',
    };
    controls.l = {
        key: 2,
        sym: 'L',
        classes: 'control-l control-button-l-r control',
        ref: React.useRef<HTMLAnchorElement|null>(null),
    };

    controls.r = {
        key: 3,
        sym: 'R',
        classes: 'control-r control-button-l-r control',
        ref: React.useRef<HTMLAnchorElement|null>(null),
    };
    controls.start = {
        ref: React.useRef<HTMLAnchorElement|null>(null),
        key: 4,
        sym: 'START',
        classes: 'control-start control-button-start-select control',
        transformX: 25,
    };
    controls.select = {
        ref: React.useRef<HTMLAnchorElement|null>(null),
        key: 5,
        sym: 'SEL',
        classes: 'control-select control-button-start-select control',
        transformX: -25,
    };
    controls.up = {
        ref: React.useRef<HTMLAnchorElement|null>(null),
        key: 6,
        sym: '^',
        transformX: 100,
        classes: 'control-up control control-pad-button',
    }
    controls.down = {
        ref: React.useRef<HTMLAnchorElement|null>(null),
        key: 7,
        sym: 'v',
        transformX: 100,
        classes: 'control-down control control-pad-button',
    }
    controls.left = {
        ref: React.useRef<HTMLAnchorElement|null>(null),
        key: 8,
        sym: '<',
        classes: 'control-left control control-pad-button',
    }
    controls.right = {
        ref: React.useRef<HTMLAnchorElement|null>(null),
        key: 9,
        sym: '>',
        transformX: 200,
        classes: 'control-right control control-pad-button',
    }

    function determineKey(e: React.TouchEvent<HTMLDivElement>, touch: React.Touch): number | null {
        const x = touch.pageX;
        const y = touch.pageY;
        for (const control of Object.keys(controls)) {
            const ref = controls[control].ref.current;
            if (ref == null) {
                console.log('No ref found');
                continue;
            }
            let top = ref.getBoundingClientRect().top + document.documentElement.scrollTop;
            const currentControl = controls[control];
            const transformX = currentControl.transformX; 
            const transformY = currentControl.transformY; 
            let offsetLeft = ref.offsetLeft;
            const offsetWidth = ref.offsetWidth;
            let offsetTop = top;
            const offsetHeight = ref.offsetHeight;
            if (transformX != null) {
                offsetLeft += offsetWidth * (transformX / 100);
            }
            if (transformY != null) {
                offsetTop += offsetHeight * (transformY / 100);
            }
            console.log(x, y, offsetLeft, offsetTop, offsetWidth, offsetHeight);
            if (x >= offsetLeft && x <= offsetLeft + offsetWidth && y >= offsetTop && y <= offsetTop + offsetHeight) {
                return controls[control].key;
            }
        }
        return null;
    }
    function touchStartControls(e: React.TouchEvent<HTMLDivElement>) {
        e.preventDefault();
        if (webSocket == null) {
            console.log('There is not websocket');
            return;
        }
        for (let i = 0; i < e.changedTouches.length; i++) {
            const touch = e.changedTouches[i];
            let key: number|null = determineKey(e, touch);
            if (key == null) {
                continue;
            }
            const idx = touch.identifier;
            onGoingTouches[idx] = key;
            sendKeyDown(webSocket, true, key);
        }
        return false;
    }
    function touchMoveControls(e: React.TouchEvent<HTMLDivElement>) {
        e.preventDefault();
        if (webSocket == null) {
            console.log('There is not websocket');
            return;
        }
        for (let i = 0; i < e.changedTouches.length; i++) {
            const touch = e.changedTouches[i];
            let key: number|null = determineKey(e, touch);
            const idx = touch.identifier;
            if (key == null) {
                continue;
            }
            if (onGoingTouches[idx] != null) {
                sendKeyDown(webSocket, false, onGoingTouches[idx]);
                delete onGoingTouches[idx];
            }
            onGoingTouches[idx] = key;
            sendKeyDown(webSocket, true, key);
        }
        return false;
    }


    function touchEndControls(e: React.TouchEvent<HTMLDivElement>) {
        e.preventDefault();
        if (webSocket == null) {
            console.log('There is not websocket');
            return;
        }
        for (let i = 0; i < e.changedTouches.length; i++) {
            const touch = e.changedTouches[i];
            const idx = touch.identifier;
            if (onGoingTouches[idx] == null) {
                return;
            }
            sendKeyDown(webSocket, false, onGoingTouches[idx]);
            delete onGoingTouches[idx];
        }
        return false;
    }

    const keyMap: string[] = ["KeyZ", "KeyX", "KeyA", "KeyS",
            "Enter", "Space", "ArrowUp", "ArrowDown",
            "ArrowLeft", "ArrowRight"];
    function onPressControl(e: React.KeyboardEvent<HTMLDivElement>) {
        if (webSocket == null) {
            console.log('There is not websocket');
            return;
        }
        let key = keyMap.findIndex((c: string) => c == e.code);
        if (key != -1) {
            e.preventDefault();
            sendKeyDown(webSocket, true, key);
        }
    }
    function onUnpressControl(e: React.KeyboardEvent<HTMLDivElement>) {
        if (webSocket == null) {
            console.log('There is not websocket');
            return;
        }
        let key = keyMap.findIndex((c: string) => c == e.code);
        if (key != -1) {
            e.preventDefault();
            sendKeyDown(webSocket, false, key);
        }
    }
    document.onselectstart = () => false;
    return (
        <div tabIndex={-1} className="overlay" onKeyDown={onPressControl} onKeyUp={onUnpressControl}> 
            <div className="vertical-padding">
            </div>
            <div className="controls" onTouchStart={touchStartControls} onTouchMove={touchMoveControls} onTouchEnd={touchEndControls}>
                <a tabIndex={-1} className="gear control" onClick={showOverlayMenu} onTouchStart={showOverlayMenu}>
                    <img src={HOME_BUTTON_IMAGE} alt="Go to menu. (House icon)"/>
                </a>
                {
                    Object.keys(controls).map((key) =>  
                        <a tabIndex={-1}
                                className={controls[key].classes}
                                ref={controls[key].ref}
                                key={key}
                                onMouseDown={(e: React.MouseEvent<HTMLAnchorElement>) => mouseDown(e, controls[key].key)}
                                onMouseUp={(e: React.MouseEvent<HTMLAnchorElement>) => mouseUp(e, controls[key].key)}>
                            {controls[key].sym}
                        </a>
                    )
                }
            </div>
        </div>
    );
}
