import {getSelect, getForm} from "./selectors";

let initialized = false;

let formEl: HTMLFormElement;
let dateEl: HTMLSelectElement;
let classroomEl: HTMLSelectElement;
let sessionEl: HTMLSelectElement;

// Cached option lists
let classroomOptions: HTMLOptionElement[] = [];
let sessionOptions: HTMLOptionElement[] = [];

// Indexes
let classroomsByDate: Map<string, HTMLOptionElement[]> = new Map();
let sessionsByDateClassroom: Map<string, Map<string, HTMLOptionElement[]>> = new Map();

let searchTimeout: number | undefined;

export function initRegistrationsPage() {
    if (!initialized) {
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', setup);
        } else {
            setup();
        }

        initialized = true;
    }
}

function setup() {
    formEl = getForm('search-session-participants');
    dateEl = getSelect('date');
    classroomEl = getSelect('classroom');
    sessionEl = getSelect('session');

    classroomOptions = Array.from(classroomEl.options);
    sessionOptions = Array.from(sessionEl.options);

    buildIndexes();

    dateEl.addEventListener('change', updateUI);
    classroomEl.addEventListener('change', updateUI);
    sessionEl.addEventListener('change', searchParticipants);
    addPrintEventListener();

    updateUI();
}

/**
 * Group options by multiple keys (many-to-many)
 */
function groupOptionsMulti(
    options: HTMLOptionElement[],
    keyFn: (opt: HTMLOptionElement) => string[]
): Map<string, HTMLOptionElement[]> {
    const map = new Map<string, HTMLOptionElement[]>();

    options.forEach(opt => {
        const keys = keyFn(opt);

        keys.forEach(key => {
            if (!key) {
                return;
            }

            if (!map.has(key)) {
                map.set(key, []);
            }

            map.get(key)!.push(opt);
        });
    });

    return map;
}

function buildIndexes() {
    // Classrooms: many-to-many (date ↔ classroom)
    classroomsByDate = groupOptionsMulti(classroomOptions, opt => {
        const raw = opt.dataset.date;

        if (!raw) {
            return [];
        }

        return raw.split(',').map(d => d.trim()).filter(Boolean);
    });

    // Sessions: date → classroom → options
    sessionsByDateClassroom = new Map();

    sessionOptions.forEach(opt => {
        const date = opt.dataset.date;
        const classroom = opt.dataset.classroom;

        if (!date || !classroom) {
            return;
        }

        if (!sessionsByDateClassroom.has(date)) {
            sessionsByDateClassroom.set(date, new Map());
        }

        const classroomMap = sessionsByDateClassroom.get(date)!;

        if (!classroomMap.has(classroom)) {
            classroomMap.set(classroom, []);
        }

        classroomMap.get(classroom)!.push(opt);
    });

    if (!classroomOptions.length) {
        console.warn('No classroom options found');
    }

    if (!sessionOptions.length) {
        console.warn('No session options found');
    }
}

/**
 * Show only selected options (via hidden attribute)
 */
function showOnly(
    all: HTMLOptionElement[],
    visible: HTMLOptionElement[]
) {
    const visibleSet = new Set(visible);

    all.forEach(opt => {
        if (opt.value === '') {
            // Always keep placeholder visible
            opt.hidden = false;
            return;
        }

        opt.hidden = !visibleSet.has(opt);
    });
}

function addPrintEventListener() {
    const el = document.getElementById('print-button') as HTMLButtonElement;
    if (el) {
        el.addEventListener('click', print);
    }
}

function print() {
    window.print();
}

function updateUI() {
    const date = dateEl.value;

    updateClassrooms(date);
    updateSessions(date);
    applyUXRules(date);
}

function updateClassrooms(date: string) {
    const visible = date ? classroomsByDate.get(date) ?? [] : [];

    showOnly(classroomOptions, visible);

    if (!isVisible(classroomEl)) {
        classroomEl.selectedIndex = 0;
    }
}

function updateSessions(date: string) {
    const classroom = classroomEl.value;

    let visible: HTMLOptionElement[] = [];

    if (date && classroom) {
        const classroomMap = sessionsByDateClassroom.get(date);

        if (classroomMap) {
            visible = classroomMap.get(classroom) ?? [];
        }
    }

    showOnly(sessionOptions, visible);

    if (!isVisible(sessionEl)) {
        sessionEl.selectedIndex = 0;
    }
}

function applyUXRules(date: string) {
    const classroom = classroomEl.value;

    classroomEl.disabled = !date;
    sessionEl.disabled = !date || !classroom;
}

function isVisible(select: HTMLSelectElement): boolean {
    const selected = select.selectedOptions[0];

    if (!selected) {
        return false;
    }

    return !selected.hidden;
}

function searchParticipants() {
    const session = sessionEl.value;

    if (!session) {
        return;
    }

    if (searchTimeout) {
        clearTimeout(searchTimeout);
    }

    searchTimeout = window.setTimeout(() => {
        formEl.submit();
    }, 0);
}