import { BooleanFlag, Event } from "@clarity-types/data";
import { InputData, InputState, Setting } from "@clarity-types/interaction";
import { bind } from "@src/core/event";
import { schedule } from "@src/core/task";
import { time } from "@src/core/time";
import { clearTimeout, setTimeout } from "@src/core/timeout";
import { get } from "@src/layout/dom";
import encode from "./encode";
import { target } from "@src/layout/target";

let timeout: number = null;
export let state: InputState[] = [];

export function start(): void {
    reset();
}

export function observe(root: Node): void {
    bind(root, "input", recompute, true);
    bind(root, "keydown", enter, true);
}

function recompute(evt: UIEvent): void {
    let input = target(evt) as HTMLInputElement;
    let value = get(input);
    if (input && input.type && value) {
        let v = input.value;
        let t = input.type;
        switch (input.type) {
            case "radio":
            case "checkbox":
                v = input.checked ? "true" : "false";
                break;
        }

        let data: InputData = { target: input, value: v, type: t, trust: evt.isTrusted ? BooleanFlag.True : BooleanFlag.False };

        // If last entry in the queue is for the same target node as the current one, remove it so we can later swap it with current data.
        if (state.length > 0 && (state[state.length - 1].data.target === data.target)) { state.pop(); }

        state.push({ time: time(evt), event: Event.Input, data });

        clearTimeout(timeout);
        timeout = setTimeout(process, Setting.InputLookAhead, Event.Input);
    }
}

function enter(evt: KeyboardEvent): void {
    if (evt.key === "Enter" && !evt.repeat && state.length > 0) {
        clearTimeout(timeout);
        process(Event.Input);
    }
}

function process(event: Event): void {
    schedule(encode.bind(this, event));
}

export function reset(): void {
    state = [];
}

export function stop(): void {
    clearTimeout(timeout);
    reset();
}