const input = (() => {
    const pollingIntervalMs = 4;
    let controllerChangedIndex = -1;

    // Libretro config
    let controllerState = {
        [KEY.B]: false,
        [KEY.Y]: false,
        [KEY.SELECT]: false,
        [KEY.START]: false,
        [KEY.UP]: false,
        [KEY.DOWN]: false,
        [KEY.LEFT]: false,
        [KEY.RIGHT]: false,
        [KEY.A]: false,
        [KEY.X]: false,
        // extra
        [KEY.L]: false,
        [KEY.R]: false,
        [KEY.L2]: false,
        [KEY.R2]: false,
        [KEY.L3]: false,
        [KEY.R3]: false
    };

    const poll = (intervalMs, callback) => {
        let _ticker = 0;
        return {
            enable: () => {
                if (_ticker > 0) return;
                log.debug(`[input] poll set to ${intervalMs}ms`);
                _ticker = setInterval(callback, intervalMs)
            },
            disable: () => {
                if (_ticker < 1) return;
                log.debug('[input] poll has been disabled');
                clearInterval(_ticker);
                _ticker = 0;
            }
        }
    };

    const controllerEncoded = [0, 0, 0, 0, 0];
    const keys = Object.keys(controllerState);

    const compare = (a, b) => {
        if (a.length !== b.length) return false;
        for (let i = 0; i < a.length; i++) {
            if (a[i] !== b[i]) {
                return false;
            }
        }
        return true;
    };


    // let lastState = controllerEncoded;

    const sendControllerState = () => {
        if (controllerChangedIndex >= 0) {
            const state = _getState();

            // log.debug(state)

            // if (compare(lastState, state)) {
            //     log.debug('!skip')
            // } else {
                event.pub(CONTROLLER_UPDATED, _encodeState(state));
            // }
            // lastState = state;
            controllerChangedIndex = -1;
        }
    };

    const setKeyState = (name, state) => {
        if (controllerState[name] !== undefined) {
            controllerState[name] = state;
            controllerChangedIndex = Math.max(controllerChangedIndex, 0);
        }
    };

    const setAxisChanged = (index, value) => {
        if (controllerEncoded[index + 1] !== undefined) {
            controllerEncoded[index + 1] = Math.floor(32767 * value);
            controllerChangedIndex = Math.max(controllerChangedIndex, index + 1);
        }
    };

    /**
     * Converts key state into a bitmap and prepends it to the axes state.
     *
     * @returns {Uint16Array} The controller state.
     * First uint16 is the controller state bitmap.
     * The other uint16 are the axes values.
     * Truncated to the last value changed.
     *
     * @private
     */
    const _encodeState = (state) => new Uint16Array(state)

    const _getState = () => {
        controllerEncoded[0] = 0;
        for (let i = 0, len = keys.length; i < len; i++) {
            controllerEncoded[0] += controllerState[keys[i]] ? 1 << i : 0;
        }
        return controllerEncoded.slice(0, controllerChangedIndex + 1);
    }

    return {
        poll: poll(pollingIntervalMs, sendControllerState),
        setKeyState,
        setAxisChanged,
    }
})(event, KEY, log);
