let iommiTableCall;

let Axios = axios;

function iommi_update_URL(params) {
    window.history.replaceState(null, null, `${window.location.pathname}?${params.toString()}`);
}

function iommi_debounce(func, wait) {
    let timeout;

    return (...args) => {
        const fn = () => func.apply(this, args);

        clearTimeout(timeout);
        timeout = setTimeout(() => fn(), wait);
    };
}

async function iommi_validate_form(params, form) {
    const iommiErrorsPath = form.getAttribute('data-iommi-errors');
    try {
        const {
            data: {global, fields},
        } = await Axios.get(`?${params.toString()}&/${iommiErrorsPath}`, {
            cancelToken: iommiTableCall.token,
        });

        const globalErrors = form.parentNode.querySelector('.iommi_query_error');
        if (global) {
            globalErrors.querySelectorAll('span').innerHTML = global.join(', ');
            globalErrors.classList.remove('hidden');
        } else {
            globalErrors.classList.add('hidden');
        }

        if (fields) {
            Object.keys(fields).forEach(key => {
                // Mark the field as invalid
                document.getElementById(key).setAttribute('invalid', '');
                // Clear all previous errors
                document
                    .getElementById(`id_error_${key}`)
                    .parentElement.querySelectorAll('.t-error')
                    .remove();

                fields[key].forEach(x => {
                    const error = document.createElement('div');
                    error.classList.add('t-error');
                    error.innerHTML = x;
                    document.getElementById(`id_error_${key}`).parentElement.appendChild(error);
                });
            });
        }
    } catch (err) {
        if (!Axios.isCancel(err)) {
            throw err;
        }
    }
}


function iommi_show_spinner(isLoading, container) {
    // TODO: implement this thing
    if (isLoading) {
        // window.showLoadingIndicator(container, 't-big');
    } else {
        // window.removeLoadingIndicator(container);
    }
}

async function iommi_query_populate(form) {
    // Cancel previous request in progress
    if (iommiTableCall) {
        iommiTableCall.cancel('Overridden by another request');
    }

    iommiTableCall = Axios.CancelToken.source();

    const formData = new FormData(form);
    const params = new URLSearchParams(formData);

    const iommi_id = form.getAttribute('data-iommi-id-of-table');
    const table = document.querySelector(`[data-iommi-id="${iommi_id}"]`)
    const container = table.closest('.iommi-table-container');

    iommi_update_URL(params);
    iommi_validate_form(params, form);
    iommi_show_spinner(true, container);
    const iommiTbodyPath = container.querySelector(`[data-iommi-id="${iommi_id}"]`).getAttribute('data-endpoint');

    try {
        const {
            data: {html},
        } = await Axios.get(`?${params.toString()}&${iommiTbodyPath}`, {
            cancelToken: iommiTableCall.token,
        });

        // We have to remove each child before setting innerHTML since disconnectedCallback
        // is not fired on the children using IE11
        let child = container.firstElementChild;
        while (child) {
            container.removeChild(child);
            child = container.firstElementChild;
        }

        const element = document.createRange().createContextualFragment(html);
        container.appendChild(element);
    } catch (err) {
        if (!Axios.isCancel(err)) {
            const errors = form.querySelector('.iommi_query_error');
            errors.innerHTML = err;
        }
    } finally {
        iommi_show_spinner(false, container);
    }
}

function iommi_has_same_data(prevData, newData) {
    return (
        [...newData].every(([key, value]) => prevData.get(key) === value) &&
        [...prevData].every(([key, value]) => newData.get(key) === value)
    );
}

function iommi_enhance_form(form) {
    let table = document.querySelector(`[data-iommi-id="${form.getAttribute('data-iommi-id-of-table')}"]`)
    const container = table.parentNode;

    form.setAttribute('autocomplete', 'off');
    const debouncedPopulate = iommi_debounce(iommi_query_populate, 400);


    let prevData = new FormData(form);
    const onChange = e => {
        const formData = new FormData(form);
        if (iommi_has_same_data(prevData, formData)) {
            return;
        }
        prevData = formData;

        if (e.target.getAttribute('type') === 'text') {
            if (e.type === 'change') {
                // change event fire when the input loses focus. We have already
                // populated the form on the input event so ignore it
                return;
            }
            iommi_show_spinner(true, container);
            // delay ajax request for free text
            debouncedPopulate(form, e.target);
        } else {
            // select2 elements have hidden inputs when they update GUI should respond immediately
            // same goes for checkboxes
            iommi_query_populate(form, container);
        }
    };
    ['change', 'input', 'switch-mode'].forEach(eventType => {
        form.addEventListener(eventType, onChange);
    });

    const elements = form.parentNode.getElementsByClassName('iommi_query_toggle_simple_mode');
    if (elements.length > 0) {
        elements[0].addEventListener('click', () => {
            const event = new CustomEvent('switch-mode', {bubbles: true});
            form.dispatchEvent(event);
        });
    }

    Array.from(form.getElementsByClassName('select2')).forEach(s => {
        s.addEventListener('change', onChange);
    });

    form.querySelector('[data-iommi-filter-button]').remove();
}

document.addEventListener('DOMContentLoaded', () => {
    document.querySelectorAll('.iommi_filter').forEach(form => iommi_enhance_form(form));
});
