import * as bootstrap from 'bootstrap';
import Swal from 'sweetalert2';
import { createIcons, icons } from 'lucide';
import QRCode from 'qrcode';
import { Html5Qrcode } from 'html5-qrcode';

window.Swal = Swal;
window.bootstrap = bootstrap;

const csrfToken = () => document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') ?? '';

const notify = (message, type = 'success') => {
    Swal.fire({
        toast: true,
        position: 'top-end',
        icon: type,
        title: message,
        showConfirmButton: false,
        timer: 2800,
        timerProgressBar: true,
    });
};

const clearFormErrors = (form) => {
    form.querySelectorAll('.ajax-form-errors, .invalid-feedback.dynamic-feedback').forEach((node) => node.remove());
    form.querySelectorAll('.is-invalid').forEach((field) => field.classList.remove('is-invalid'));
};

const renderFormErrors = (form, data) => {
    clearFormErrors(form);

    const errors = data?.errors ?? {};
    const messages = Object.values(errors).flat();

    const box = document.createElement('div');
    box.className = 'ajax-form-errors alert alert-danger';

    const title = document.createElement('strong');
    title.textContent = data?.message ?? 'Angalia taarifa hizi:';
    box.appendChild(title);

    if (messages.length) {
        const list = document.createElement('ul');
        list.className = 'mb-0 mt-2';
        messages.forEach((message) => {
            const item = document.createElement('li');
            item.textContent = message;
            list.appendChild(item);
        });
        box.appendChild(list);
    }

    form.prepend(box);

    Object.entries(errors).forEach(([name, fieldMessages]) => {
        const selector = `[name="${CSS.escape(name)}"], [name="${CSS.escape(`${name}[]`)}"]`;
        const field = form.querySelector(selector);
        if (!field) return;

        field.classList.add('is-invalid');
        const feedback = document.createElement('div');
        feedback.className = 'invalid-feedback dynamic-feedback d-block';
        feedback.textContent = fieldMessages[0];
        (field.closest('.modern-phone-frame') ?? field.closest('.input-icon') ?? field).insertAdjacentElement('afterend', feedback);
    });
};

const refreshFragment = async (selector) => {
    if (!selector) return;

    const current = document.querySelector(selector);
    if (!current) return;

    const response = await fetch(window.location.href, {
        headers: {
            Accept: 'text/html',
            'X-Requested-With': 'XMLHttpRequest',
        },
    });

    if (!response.ok) return;

    const html = await response.text();
    const page = new DOMParser().parseFromString(html, 'text/html');
    const fresh = page.querySelector(selector);

    if (!fresh) return;

    current.replaceWith(fresh);
    createIcons({ icons });
    setupPasswordToggles();
    setupPhoneInputs(fresh);
};

const replaceFragmentFromHtml = (html, selector) => {
    if (!selector) return false;

    const current = document.querySelector(selector);
    if (!current) return false;

    const page = new DOMParser().parseFromString(html, 'text/html');
    const fresh = page.querySelector(selector);
    if (!fresh) return false;

    current.replaceWith(fresh);
    createIcons({ icons });
    setupPasswordToggles();
    setupPhoneInputs(fresh);

    return true;
};

const ajaxSubmitForm = async (form) => {
    clearFormErrors(form);

    const submitter = form.querySelector('button[type="submit"]:not([disabled]), button:not([type]):not([disabled]), input[type="submit"]:not([disabled])');
    const originalSubmitterHtml = submitter?.innerHTML;

    if (submitter) {
        submitter.disabled = true;
        submitter.classList.add('is-submitting');
        submitter.innerHTML = '<span class="spinner-border spinner-border-sm" aria-hidden="true"></span><span>Saving...</span>';
    }

    try {
        const response = await fetch(form.action, {
            method: 'POST',
            headers: {
                Accept: 'application/json',
                'X-CSRF-TOKEN': csrfToken(),
                'X-Requested-With': 'XMLHttpRequest',
            },
            body: new FormData(form),
        });

        const data = await response.json().catch(() => ({
            message: 'Request failed. Tafadhali jaribu tena.',
        }));

        if (response.status === 422) {
            renderFormErrors(form, data);
            return;
        }

        if (!response.ok) {
            throw new Error(data.message ?? 'Request failed. Tafadhali jaribu tena.');
        }

        const modal = form.closest('.modal');
        if (modal) {
            bootstrap.Modal.getInstance(modal)?.hide();
        }

        const result = await Swal.fire({
            icon: 'success',
            title: 'Imefanikiwa',
            text: data.message ?? 'Taarifa zimehifadhiwa.',
            confirmButtonText: 'OK',
            confirmButtonColor: '#5f46c7',
        });

        if (result.isConfirmed) {
            await refreshFragment(data.refresh_target ?? form.dataset.refreshTarget);
        }
    } catch (error) {
        Swal.fire({
            icon: 'error',
            title: 'Haijakamilika',
            text: error.message || 'Kuna tatizo limetokea.',
            confirmButtonText: 'OK',
            confirmButtonColor: '#b42318',
        });
    } finally {
        if (submitter) {
            submitter.disabled = false;
            submitter.classList.remove('is-submitting');
            submitter.innerHTML = originalSubmitterHtml;
            createIcons({ icons });
        }

        delete form.dataset.confirmed;
    }
};

const postAttendance = async (payload) => {
    const response = await fetch(document.body.dataset.attendanceUrl, {
        method: 'POST',
        headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
            'X-CSRF-TOKEN': csrfToken(),
        },
        body: JSON.stringify(payload),
    });

    const data = await response.json().catch(() => ({ message: 'Request failed.' }));

    if (!response.ok) {
        throw new Error(data.message ?? 'Attendance haikuhifadhiwa.');
    }

    return data;
};

const setupManualAttendance = () => {
    document.addEventListener('click', async (event) => {
        const button = event.target.closest('[data-attendance-member]');
        if (!button) return;

        const serviceId = document.querySelector('#manual-service-id')?.value;
        if (!serviceId) {
            notify('Chagua service/event kwanza.', 'warning');
            return;
        }

        button.disabled = true;
        button.classList.add('is-loading');

        try {
            const data = await postAttendance({
                church_service_id: serviceId,
                member_id: button.dataset.attendanceMember,
                method: 'manual',
            });

            button.innerHTML = '<i data-lucide="check"></i><span>Present</span>';
            button.classList.remove('btn-outline-primary');
            button.classList.add('btn-success');
            notify(data.message);
            createIcons({ icons });
        } catch (error) {
            button.disabled = false;
            notify(error.message, 'warning');
        } finally {
            button.classList.remove('is-loading');
        }
    });
};

const setupQrCards = () => {
    document.querySelectorAll('[data-qr-token]').forEach((canvas) => {
        QRCode.toCanvas(canvas, canvas.dataset.qrToken, {
            width: Number(canvas.dataset.qrSize ?? 168),
            margin: 1,
            color: {
                dark: '#132f2b',
                light: '#ffffff',
            },
        });
    });
};

const appendScanRecord = (record) => {
    const list = document.querySelector('#scan-records');
    if (!list || !record?.member) return;

    const item = document.createElement('div');
    item.className = 'scan-row';
    item.innerHTML = `
        <div>
            <strong>${record.member.first_name} ${record.member.last_name}</strong>
            <span>${record.member.jumuiya?.name ?? 'No Jumuiya'}</span>
        </div>
        <em>${record.method.toUpperCase()}</em>
    `;
    list.prepend(item);
};

const setupQrScanner = () => {
    const reader = document.querySelector('#qr-reader');
    const startButton = document.querySelector('#start-qr-scanner');
    const stopButton = document.querySelector('#stop-qr-scanner');
    const serviceSelect = document.querySelector('#qr-service-id');

    if (!reader || !startButton || !serviceSelect) return;

    let scanner = null;
    let busy = false;

    startButton.addEventListener('click', async () => {
        if (!serviceSelect.value) {
            notify('Chagua service/event kabla ya kuscan.', 'warning');
            return;
        }

        scanner = scanner ?? new Html5Qrcode('qr-reader');

        try {
            await scanner.start(
                { facingMode: 'environment' },
                { fps: 10, qrbox: { width: 250, height: 250 } },
                async (decodedText) => {
                    if (busy) return;
                    busy = true;
                    scanner.pause(true);

                    try {
                        const data = await postAttendance({
                            church_service_id: serviceSelect.value,
                            qr_token: decodedText,
                            method: 'qr',
                        });
                        notify(data.message);
                        appendScanRecord(data.record);
                    } catch (error) {
                        notify(error.message, 'warning');
                    } finally {
                        setTimeout(() => {
                            busy = false;
                            scanner.resume();
                        }, 1600);
                    }
                },
            );

            startButton.classList.add('d-none');
            stopButton?.classList.remove('d-none');
        } catch (error) {
            notify(error.message || 'Camera haikuweza kufunguka.', 'error');
        }
    });

    stopButton?.addEventListener('click', async () => {
        if (!scanner) return;
        await scanner.stop();
        startButton.classList.remove('d-none');
        stopButton.classList.add('d-none');
    });
};

const setupFormHandlers = () => {
    document.addEventListener('submit', async (event) => {
        const form = event.target.closest('form');
        if (!form) return;

        if (form.matches('[data-confirm-delete]') && form.dataset.confirmed !== 'true') {
            event.preventDefault();

            const result = await Swal.fire({
                title: 'Una uhakika?',
                text: form.dataset.confirmDelete || 'Taarifa hii itaondolewa.',
                icon: 'warning',
                showCancelButton: true,
                confirmButtonText: 'Ndiyo, endelea',
                cancelButtonText: 'Ghairi',
                confirmButtonColor: '#b42318',
            });

            if (!result.isConfirmed) return;

            form.dataset.confirmed = 'true';

            if (form.matches('[data-ajax-form]')) {
                await ajaxSubmitForm(form);
                return;
            }

            HTMLFormElement.prototype.submit.call(form);
            return;
        }

        if (!form.matches('[data-ajax-form]')) return;

        event.preventDefault();
        await ajaxSubmitForm(form);
    });
};

const autoFilterTimers = new WeakMap();
const autoFilterControllers = new WeakMap();

const buildAutoFilterUrl = (form) => {
    const rawAction = form.getAttribute('action') || window.location.pathname;
    const url = new URL(rawAction, window.location.origin);
    const formData = new FormData(form);

    url.search = '';

    formData.forEach((value, key) => {
        if (key.startsWith('_')) return;
        if (String(value).trim() === '') return;
        url.searchParams.append(key, value);
    });

    return url;
};

const runAutoFilter = async (form) => {
    const method = (form.method || 'GET').toUpperCase();
    const target = form.dataset.refreshTarget;
    const previous = autoFilterControllers.get(form);

    if (previous) previous.abort();

    const controller = new AbortController();
    autoFilterControllers.set(form, controller);
    form.classList.add('is-filtering');

    try {
        let response;
        let nextUrl = null;

        if (method === 'GET') {
            nextUrl = buildAutoFilterUrl(form);
            response = await fetch(nextUrl, {
                headers: {
                    Accept: 'text/html',
                    'X-Requested-With': 'XMLHttpRequest',
                },
                signal: controller.signal,
            });
        } else {
            response = await fetch(form.action, {
                method,
                headers: {
                    Accept: 'text/html',
                    'X-CSRF-TOKEN': csrfToken(),
                    'X-Requested-With': 'XMLHttpRequest',
                },
                body: new FormData(form),
                signal: controller.signal,
            });

            if (response.url) nextUrl = new URL(response.url);
        }

        if (!response.ok) throw new Error('Filter haikuweza kukamilika.');

        const html = await response.text();
        if (!replaceFragmentFromHtml(html, target)) {
            window.location.assign(nextUrl?.toString() || form.action);
            return;
        }

        if (nextUrl && nextUrl.origin === window.location.origin) {
            window.history.replaceState({}, '', nextUrl);
        }
    } catch (error) {
        if (error.name !== 'AbortError') notify(error.message || 'Filter imekwama.', 'error');
    } finally {
        form.classList.remove('is-filtering');
    }
};

const scheduleAutoFilter = (form, delay = 450) => {
    clearTimeout(autoFilterTimers.get(form));
    autoFilterTimers.set(form, setTimeout(() => runAutoFilter(form), delay));
};

const setupAutoFilters = () => {
    document.addEventListener('submit', (event) => {
        const form = event.target.closest('form[data-auto-filter]');
        if (!form) return;

        event.preventDefault();
        runAutoFilter(form);
    });

    document.addEventListener('input', (event) => {
        const field = event.target.closest('input, textarea');
        const form = field?.closest('form[data-auto-filter]');
        if (!field || !form || field.type === 'hidden') return;

        scheduleAutoFilter(form, Number(form.dataset.autoFilterDelay ?? 450));
    });

    document.addEventListener('change', (event) => {
        const field = event.target.closest('select, input[type="checkbox"], input[type="radio"]');
        const form = field?.closest('form[data-auto-filter]');
        if (!field || !form) return;

        scheduleAutoFilter(form, 40);
    });
};

const setupPasswordToggles = () => {
    document.querySelectorAll('[data-password-toggle]').forEach((button) => {
        if (button.dataset.passwordToggleReady === 'true') return;
        button.dataset.passwordToggleReady = 'true';

        button.addEventListener('click', () => {
            const input = document.querySelector(button.dataset.passwordToggle);
            if (!input) return;

            const visible = input.getAttribute('type') === 'text';
            input.setAttribute('type', visible ? 'password' : 'text');
            button.innerHTML = visible ? '<i data-lucide="eye"></i>' : '<i data-lucide="eye-off"></i>';
            createIcons({ icons });
        });
    });
};

const setupRemoteModals = () => {
    const modal = document.querySelector('#remoteFormModal');
    const content = modal?.querySelector('.remote-modal-content');
    if (!modal || !content) return;

    modal.addEventListener('hidden.bs.modal', () => {
        content.innerHTML = '';
    });

    document.addEventListener('click', async (event) => {
        const trigger = event.target.closest('[data-modal-url]');
        if (!trigger) return;

        event.preventDefault();

        const instance = bootstrap.Modal.getOrCreateInstance(modal);
        content.innerHTML = `
            <div class="modal-body remote-modal-loading">
                <div class="church-loader"></div>
                <strong>Loading form...</strong>
            </div>
        `;
        instance.show();

        try {
            const response = await fetch(trigger.dataset.modalUrl, {
                headers: {
                    Accept: 'text/html',
                    'X-Requested-With': 'XMLHttpRequest',
                },
            });

            if (!response.ok) throw new Error('Form haikuweza kufunguka.');

            content.innerHTML = await response.text();
            createIcons({ icons });
            setupPasswordToggles();
            setupPhoneInputs(content);
        } catch (error) {
            content.innerHTML = `
                <div class="modal-header">
                    <h5 class="modal-title">Haijafunguka</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body">
                    <div class="alert alert-danger mb-0">${error.message || 'Kuna tatizo limetokea.'}</div>
                </div>
            `;
        }
    });
};

const phoneCountries = [
    { code: 'TZ', label: 'Tanzania', dial: '+255', max: 9 },
    { code: 'KE', label: 'Kenya', dial: '+254', max: 9 },
    { code: 'UG', label: 'Uganda', dial: '+256', max: 9 },
    { code: 'RW', label: 'Rwanda', dial: '+250', max: 9 },
    { code: 'BI', label: 'Burundi', dial: '+257', max: 8 },
];

const groupPhoneDigits = (value, max = 12) => value
    .replace(/\D/g, '')
    .slice(0, max)
    .replace(/(\d{3})(?=\d)/g, '$1 ')
    .trim();

const selectedPhoneCountry = (dial) => phoneCountries.find((country) => country.dial === dial) ?? phoneCountries[0];

const parsePhoneValue = (value) => {
    const clean = value.trim();
    const defaultCountry = phoneCountries[0];

    if (!clean) {
        return { dial: defaultCountry.dial, national: '' };
    }

    let digits = clean.replace(/\D/g, '');
    const matched = phoneCountries.find((country) => digits.startsWith(country.dial.replace(/\D/g, '')));

    if (matched) {
        return {
            dial: matched.dial,
            national: groupPhoneDigits(digits.slice(matched.dial.replace(/\D/g, '').length), matched.max),
        };
    }

    if (digits.startsWith('0')) {
        digits = digits.slice(1);
    }

    return {
        dial: defaultCountry.dial,
        national: groupPhoneDigits(digits, defaultCountry.max),
    };
};

const syncPhoneFrame = (frame) => {
    const original = frame.querySelector('[data-phone-input]');
    const dialSelect = frame.querySelector('[data-phone-dial]');
    const nationalInput = frame.querySelector('[data-phone-national]');
    const counter = frame.querySelector('[data-phone-counter]');
    const countryCode = frame.querySelector('[data-phone-country-code]');

    if (!original || !dialSelect || !nationalInput) return;

    const country = selectedPhoneCountry(dialSelect.value);
    const digits = nationalInput.value.replace(/\D/g, '').slice(0, country.max);

    nationalInput.value = groupPhoneDigits(digits, country.max);
    original.value = digits ? `${country.dial} ${nationalInput.value}` : '';

    if (countryCode) countryCode.textContent = country.code;
    if (counter) {
        counter.textContent = `${digits.length}/${country.max}`;
        counter.classList.toggle('is-complete', digits.length >= country.max);
    }
};

const enhancePhoneInput = (input) => {
    if (input.dataset.phoneEnhanced === 'true') return;

    const iconWrap = input.closest('.input-icon');
    const { dial, national } = parsePhoneValue(input.value);
    const activeCountry = selectedPhoneCountry(dial);
    const frame = document.createElement('div');
    frame.className = 'modern-phone-frame';
    frame.dataset.phoneFrame = 'true';

    const chip = document.createElement('span');
    chip.className = 'phone-country-chip';
    chip.innerHTML = '<span class="phone-country-flag" data-phone-country-code></span>';

    const dialSelect = document.createElement('select');
    dialSelect.className = 'phone-dial-select';
    dialSelect.dataset.phoneDial = 'true';
    dialSelect.setAttribute('aria-label', 'Country code');

    phoneCountries.forEach((country) => {
        const option = document.createElement('option');
        option.value = country.dial;
        option.textContent = country.dial;
        option.selected = country.dial === activeCountry.dial;
        dialSelect.appendChild(option);
    });

    const nationalInput = document.createElement('input');
    nationalInput.className = 'phone-national-input';
    nationalInput.dataset.phoneNational = 'true';
    nationalInput.type = 'tel';
    nationalInput.inputMode = 'tel';
    nationalInput.placeholder = '700 000 000';
    nationalInput.value = national;
    nationalInput.required = input.required;

    const counter = document.createElement('span');
    counter.className = 'phone-digit-counter';
    counter.dataset.phoneCounter = 'true';

    input.dataset.phoneEnhanced = 'true';
    input.required = false;
    input.type = 'hidden';
    input.classList.remove('form-control');

    if (iconWrap) {
        frame.append(chip, dialSelect, nationalInput, counter, input);
        iconWrap.replaceWith(frame);
    } else {
        input.replaceWith(frame);
        frame.append(chip, dialSelect, nationalInput, counter, input);
    }

    const update = () => syncPhoneFrame(frame);
    nationalInput.addEventListener('input', update);
    nationalInput.addEventListener('blur', update);
    dialSelect.addEventListener('change', update);

    update();
};

const setupPhoneInputs = (root = document) => {
    root.querySelectorAll('[data-phone-input]').forEach(enhancePhoneInput);

    if (document.body.dataset.phoneSubmitReady === 'true') return;
    document.body.dataset.phoneSubmitReady = 'true';

    document.addEventListener('submit', (event) => {
        event.target.querySelectorAll('[data-phone-frame]').forEach(syncPhoneFrame);
    });
};

const setupResponsiveSidebar = () => {
    const desktopQuery = window.matchMedia('(min-width: 992px)');
    const shell = document.querySelector('#app-shell');
    const toggles = document.querySelectorAll('[data-sidebar-toggle]');

    const setCollapsed = (collapsed) => {
        document.body.classList.toggle('sidebar-collapsed', collapsed);
        shell?.classList.toggle('sidebar-collapsed', collapsed);
        toggles.forEach((button) => button.setAttribute('aria-pressed', collapsed ? 'true' : 'false'));
        localStorage.setItem('anglican.sidebar', collapsed ? 'collapsed' : 'expanded');
    };

    const closeSidebar = () => {
        document.body.classList.remove('sidebar-open');
    };

    if (desktopQuery.matches && localStorage.getItem('anglican.sidebar') === 'collapsed') {
        setCollapsed(true);
    }

    document.addEventListener('click', (event) => {
        if (event.target.closest('[data-sidebar-toggle]')) {
            if (desktopQuery.matches) {
                setCollapsed(!document.body.classList.contains('sidebar-collapsed'));
                closeSidebar();
            } else {
                document.body.classList.toggle('sidebar-open');
            }
            return;
        }

        if (event.target.closest('[data-sidebar-close]')) {
            closeSidebar();
            return;
        }

        if (window.matchMedia('(max-width: 991.98px)').matches && event.target.closest('.app-sidebar .sidebar-link')) {
            closeSidebar();
        }
    });

    document.addEventListener('keydown', (event) => {
        if (event.key === 'Escape') closeSidebar();
    });

    window.addEventListener('resize', () => {
        if (desktopQuery.matches) {
            closeSidebar();
        } else {
            setCollapsed(false);
        }
    });
};

const showFlashMessages = () => {
    if (document.body.dataset.successMessage) notify(document.body.dataset.successMessage);
    if (document.body.dataset.errorMessage) notify(document.body.dataset.errorMessage, 'error');
};

const hideLoader = () => {
    const loader = document.querySelector('#page-loader');
    if (!loader) return;
    loader.classList.add('loader-hidden');
    setTimeout(() => loader.remove(), 300);
};

document.addEventListener('DOMContentLoaded', () => {
    createIcons({ icons });
    setupManualAttendance();
    setupQrCards();
    setupQrScanner();
    setupFormHandlers();
    setupAutoFilters();
    setupRemoteModals();
    setupPhoneInputs();
    setupResponsiveSidebar();
    setupPasswordToggles();
    showFlashMessages();
});

window.addEventListener('load', hideLoader);
