const initializeGooglePopupLinks = () => {
    const links = document.querySelectorAll('[data-google-popup]');

    if (! links.length) {
        return;
    }

    const popupFeatures = () => {
        const width = 520;
        const height = 680;
        const left = Math.max(0, window.screenX + (window.outerWidth - width) / 2);
        const top = Math.max(0, window.screenY + (window.outerHeight - height) / 2);

        return [
            'popup=yes',
            `width=${width}`,
            `height=${height}`,
            `left=${Math.round(left)}`,
            `top=${Math.round(top)}`,
            'resizable=yes',
            'scrollbars=yes',
        ].join(',');
    };

    links.forEach((link) => {
        link.addEventListener('click', (event) => {
            event.preventDefault();

            const authUrl = new URL(link.href, window.location.href);
            authUrl.searchParams.set('popup', '1');
            authUrl.searchParams.set('origin', window.location.origin);

            const popup = window.open(authUrl.toString(), 'remotematch_google_signin', popupFeatures());

            if (! popup) {
                window.location.assign(authUrl.toString());

                return;
            }

            popup.focus();
        });
    });
};

const initializeAuthModal = () => {
    const modal = document.querySelector('[data-auth-modal]');
    const openButtons = document.querySelectorAll('[data-auth-modal-open]');
    const closeButton = document.querySelector('[data-auth-modal-close]');

    if (! modal || ! closeButton) {
        return;
    }

    const panels = modal.querySelectorAll('[data-auth-panel]');
    const panelButtons = modal.querySelectorAll('[data-auth-panel-target]');
    const title = modal.querySelector('[data-auth-title]');
    const eyebrow = modal.querySelector('[data-auth-eyebrow]');
    const copy = modal.querySelector('[data-auth-copy]');
    const messageBox = modal.querySelector('[data-auth-message]');
    const errorBox = modal.querySelector('[data-auth-error]');
    const forgotForm = modal.querySelector('[data-auth-forgot-form]');
    const resetForm = modal.querySelector('[data-auth-reset-form]');
    const resetEmail = modal.querySelector('[data-auth-reset-email]');
    const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') ?? '';

    const panelContent = {
        login: {
            eyebrow: 'Applicant login',
            title: 'Continue to RemoteMatch',
            copy: 'Login with Google or your username/email and password.',
        },
        forgot: {
            eyebrow: 'Password recovery',
            title: 'Verify your email with an OTP',
            copy: 'Enter your account email. We will send a short-lived verification code.',
        },
        reset: {
            eyebrow: 'OTP verification',
            title: 'Set a new password',
            copy: 'Enter the OTP from your email and choose a new password.',
        },
    };

    const hideMessage = () => {
        messageBox?.classList.add('hidden');
        if (messageBox) {
            messageBox.textContent = '';
        }
    };

    const showMessage = (message) => {
        if (! messageBox) {
            return;
        }

        messageBox.textContent = message;
        messageBox.classList.remove('hidden');
    };

    const hideError = () => {
        errorBox?.classList.add('hidden');
        if (errorBox) {
            errorBox.innerHTML = '';
        }
    };

    const escapeHtml = (value) => String(value)
        .replaceAll('&', '&amp;')
        .replaceAll('<', '&lt;')
        .replaceAll('>', '&gt;')
        .replaceAll('"', '&quot;')
        .replaceAll("'", '&#039;');

    const showError = (messages) => {
        if (! errorBox) {
            return;
        }

        const list = Array.isArray(messages) ? messages : [messages || 'Something went wrong. Please try again.'];
        errorBox.innerHTML = `<p class="font-bold">Please check the details.</p><ul class="mt-2 list-disc space-y-1 pl-5">${list.map((message) => `<li>${escapeHtml(message)}</li>`).join('')}</ul>`;
        errorBox.classList.remove('hidden');
    };

    const switchPanel = (panelName, options = {}) => {
        panels.forEach((panel) => {
            panel.classList.toggle('hidden', panel.dataset.authPanel !== panelName);
        });

        const content = panelContent[panelName] ?? panelContent.login;
        if (eyebrow) eyebrow.textContent = content.eyebrow;
        if (title) title.textContent = content.title;
        if (copy) copy.textContent = content.copy;

        if (! options.keepMessage) {
            hideMessage();
        }

        if (! options.keepError) {
            hideError();
        }
    };

    const openModal = () => {
        modal.classList.remove('hidden');
        modal.setAttribute('aria-hidden', 'false');
        document.body.classList.add('overflow-hidden');
        closeButton.focus();
    };

    const closeModal = () => {
        modal.classList.add('hidden');
        modal.setAttribute('aria-hidden', 'true');
        document.body.classList.remove('overflow-hidden');
    };

    openButtons.forEach((button) => {
        button.addEventListener('click', (event) => {
            event.preventDefault();
            openModal();
        });
    });

    closeButton.addEventListener('click', closeModal);

    panelButtons.forEach((button) => {
        button.addEventListener('click', () => {
            switchPanel(button.dataset.authPanelTarget || 'login');
        });
    });

    const jsonRequest = async (form) => {
        const response = await fetch(form.action, {
            method: form.method || 'POST',
            body: new FormData(form),
            headers: {
                'Accept': 'application/json',
                'X-CSRF-TOKEN': csrfToken,
            },
        });

        let payload = {};

        try {
            payload = await response.json();
        } catch {
            payload = {};
        }

        if (! response.ok) {
            const messages = payload.errors ? Object.values(payload.errors).flat() : [payload.message];
            const error = new Error('Request failed.');
            error.messages = messages.filter(Boolean);
            throw error;
        }

        return payload;
    };

    const setSubmitting = (form, isSubmitting) => {
        const button = form.querySelector('[data-auth-submit]');

        if (! button) {
            return;
        }

        if (! button.dataset.originalText) {
            button.dataset.originalText = button.textContent.trim();
        }

        button.disabled = isSubmitting;
        button.textContent = isSubmitting ? 'Please wait...' : button.dataset.originalText;
    };

    forgotForm?.addEventListener('submit', async (event) => {
        event.preventDefault();
        hideMessage();
        hideError();
        setSubmitting(forgotForm, true);

        try {
            const payload = await jsonRequest(forgotForm);
            if (resetEmail && payload.email) {
                resetEmail.value = payload.email;
            }
            switchPanel('reset');
            showMessage(payload.message || 'If this email exists, a password reset OTP has been sent.');
        } catch (error) {
            showError(error.messages || error.message);
        } finally {
            setSubmitting(forgotForm, false);
        }
    });

    resetForm?.addEventListener('submit', async (event) => {
        event.preventDefault();
        hideMessage();
        hideError();
        setSubmitting(resetForm, true);

        try {
            const payload = await jsonRequest(resetForm);
            resetForm.reset();
            switchPanel('login');
            showMessage(payload.message || 'Your password has been reset. You can now login.');
        } catch (error) {
            showError(error.messages || error.message);
        } finally {
            setSubmitting(resetForm, false);
        }
    });

    if (modal.dataset.authModalInitialOpen === '1') {
        openModal();
    }
};

const initializeSavedJobForms = () => {
    const forms = document.querySelectorAll('[data-save-job-form]');

    if (! forms.length) {
        return;
    }

    const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') ?? '';
    const savedOnlyView = new URLSearchParams(window.location.search).get('saved') === '1';

    const setFormState = (form, saved) => {
        const methodInput = form.querySelector('input[name="_method"]');
        const button = form.querySelector('[data-save-job-button]');

        form.dataset.saved = saved ? '1' : '0';
        form.action = saved ? form.dataset.unsaveUrl : form.dataset.saveUrl;

        if (saved) {
            if (! methodInput) {
                const input = document.createElement('input');
                input.type = 'hidden';
                input.name = '_method';
                input.value = 'DELETE';
                form.appendChild(input);
            } else {
                methodInput.value = 'DELETE';
            }
        } else if (methodInput) {
            methodInput.remove();
        }

        if (button) {
            button.textContent = saved ? (form.dataset.savedLabel || 'Saved') : (form.dataset.saveLabel || 'Save job');
            button.setAttribute('aria-pressed', saved ? 'true' : 'false');
        }
    };

    const setSubmitting = (form, isSubmitting) => {
        const button = form.querySelector('[data-save-job-button]');

        if (! button) {
            return;
        }

        if (! button.dataset.originalText) {
            button.dataset.originalText = button.textContent.trim();
        }

        button.disabled = isSubmitting;

        if (isSubmitting) {
            button.textContent = 'Saving...';

            return;
        }

        setFormState(form, form.dataset.saved === '1');
    };

    const updateSavedCount = (count) => {
        if (count === undefined || count === null) {
            return;
        }

        document.querySelectorAll('[data-saved-count]').forEach((element) => {
            element.textContent = count;
        });

        document.querySelectorAll('[data-saved-count-label]').forEach((element) => {
            element.textContent = `${count} saved`;
        });
    };

    const updateMatchingForms = (jobId, saved) => {
        document.querySelectorAll('[data-save-job-form]').forEach((form) => {
            if (form.dataset.jobId === jobId) {
                setFormState(form, saved);
            }
        });
    };

    const showInlineError = (form, message) => {
        let error = form.querySelector('[data-save-job-error]');

        if (! error) {
            error = document.createElement('p');
            error.className = 'mt-2 text-xs font-bold text-rose-700';
            error.dataset.saveJobError = '1';
            form.appendChild(error);
        }

        error.textContent = message || 'Could not update saved job. Please try again.';
    };

    forms.forEach((form) => {
        form.addEventListener('submit', async (event) => {
            event.preventDefault();

            const jobId = form.dataset.jobId;
            const wasSaved = form.dataset.saved === '1';

            setSubmitting(form, true);

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

                const payload = await response.json().catch(() => ({}));

                if (! response.ok) {
                    throw new Error(payload.message || 'Could not update saved job.');
                }

                const isSaved = Boolean(payload.saved);
                updateMatchingForms(jobId, isSaved);
                updateSavedCount(payload.saved_count);

                if (savedOnlyView && wasSaved && ! isSaved) {
                    form.closest('[data-job-card]')?.remove();
                }
            } catch (error) {
                setFormState(form, wasSaved);
                showInlineError(form, error.message);
            } finally {
                setSubmitting(form, false);
            }
        });
    });
};

const initializeFilterSheet = () => {
    const sheet = document.querySelector('[data-filter-sheet]');
    const open = document.querySelector('[data-open-filters]');
    const closeButtons = document.querySelectorAll('[data-close-filters]');

    if (! sheet || ! open || open.dataset.filterSheetInitialized === '1') {
        return;
    }

    open.dataset.filterSheetInitialized = '1';

    open.addEventListener('click', () => {
        sheet.classList.remove('hidden');
        document.body.classList.add('overflow-hidden');
    });

    closeButtons.forEach((button) => {
        button.addEventListener('click', () => {
            sheet.classList.add('hidden');
            document.body.classList.remove('overflow-hidden');
        });
    });
};

const initializeJobAssistantForms = () => {
    const forms = document.querySelectorAll('[data-ai-assist-form]');

    if (! forms.length) {
        return;
    }

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

    forms.forEach((form) => {
        if (form.dataset.initialized === '1') {
            return;
        }

        form.dataset.initialized = '1';

        form.addEventListener('submit', async (event) => {
            event.preventDefault();

            const panel = form.closest('[data-ai-panel]');
            const button = form.querySelector('[data-ai-assist-button]');
            const output = panel?.querySelector('[data-ai-output]');
            const error = form.querySelector('[data-ai-error]');
            const originalText = button?.textContent.trim() || 'Generate';

            if (error) {
                error.classList.add('hidden');
                error.textContent = '';
            }

            if (button) {
                button.disabled = true;
                button.textContent = 'Generating...';
            }

            if (output) {
                output.textContent = 'Generating AI output. This may take a few seconds...';
            }

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

                if (! response.ok) {
                    throw new Error(payload.message || 'AI generation failed.');
                }

                if (output) {
                    output.textContent = payload.content || 'Generated, but no content was returned.';
                }

                const regenerate = form.querySelector('input[name="regenerate"]');
                if (regenerate) {
                    regenerate.value = '1';
                }

                if (button) {
                    button.textContent = 'Regenerate';
                }
            } catch (exception) {
                if (error) {
                    error.textContent = exception.message || 'AI generation failed.';
                    error.classList.remove('hidden');
                }
            } finally {
                if (button) {
                    button.disabled = false;
                    if (button.textContent === 'Generating...') {
                        button.textContent = originalText;
                    }
                }
            }
        });
    });
};

const initializeJobNoteForms = () => {
    const forms = document.querySelectorAll('[data-job-note-form]');

    if (! forms.length) {
        return;
    }

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

    forms.forEach((form) => {
        if (form.dataset.initialized === '1') {
            return;
        }

        form.dataset.initialized = '1';

        form.addEventListener('submit', async (event) => {
            event.preventDefault();

            const button = form.querySelector('[data-job-note-button]');
            const status = form.querySelector('[data-job-note-status]');
            const originalText = button?.textContent.trim() || 'Save note';

            if (status) {
                status.classList.add('hidden');
                status.textContent = '';
            }

            if (button) {
                button.disabled = true;
                button.textContent = 'Saving...';
            }

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

                if (! response.ok) {
                    throw new Error(payload.message || 'Could not save note.');
                }

                if (status) {
                    status.textContent = payload.message || 'Job note saved.';
                    status.classList.remove('text-rose-700');
                    status.classList.add('text-teal-700');
                    status.classList.remove('hidden');
                }
            } catch (exception) {
                if (status) {
                    status.textContent = exception.message || 'Could not save note.';
                    status.classList.remove('hidden');
                    status.classList.remove('text-teal-700');
                    status.classList.add('text-rose-700');
                }
            } finally {
                if (button) {
                    button.disabled = false;
                    button.textContent = originalText;
                }
            }
        });
    });
};

const ensurePageLoader = () => {
    let loader = document.querySelector('[data-page-loader]');

    if (loader) {
        return loader;
    }

    loader = document.createElement('div');
    loader.className = 'page-loader';
    loader.dataset.pageLoader = '1';
    loader.setAttribute('aria-hidden', 'true');
    loader.innerHTML = `
        <div class="page-loader-bar" aria-hidden="true"></div>
        <div class="page-loader-card" role="status" aria-live="polite" aria-label="Loading">
            <span class="page-loader-orbit" aria-hidden="true">
                <span></span>
                <span></span>
                <span></span>
            </span>
            <span class="page-loader-status">Loading</span>
        </div>
    `;

    document.body.appendChild(loader);

    return loader;
};

const showPageLoader = () => {
    const loader = ensurePageLoader();

    loader.setAttribute('aria-hidden', 'false');
    requestAnimationFrame(() => loader.classList.add('is-visible'));
};

const hidePageLoader = () => {
    const loader = document.querySelector('[data-page-loader]');

    if (! loader) {
        return;
    }

    loader.classList.remove('is-visible');
    loader.setAttribute('aria-hidden', 'true');
};

const initializePage = () => {
    initializeGooglePopupLinks();
    initializeAuthModal();
    initializeSavedJobForms();
    initializeFilterSheet();
    initializeJobAssistantForms();
    initializeJobNoteForms();
};

const initializePjax = () => {
    if (window.__remoteMatchPjaxInitialized) {
        return;
    }

    window.__remoteMatchPjaxInitialized = true;

    const rootSelector = '[data-pjax-root]';
    let isNavigating = false;
    const pageCache = new Map();

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

    const isEligibleUrl = (url) => {
        if (url.origin !== window.location.origin) {
            return false;
        }

        return ! url.pathname.startsWith('/admin')
            && ! url.pathname.startsWith('/livewire')
            && ! url.pathname.startsWith('/auth/google');
    };

    const shouldIgnoreLink = (event, link) => {
        if (event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) {
            return true;
        }

        if (! link || link.target || link.hasAttribute('download')) {
            return true;
        }

        if (link.hasAttribute('data-no-pjax') || link.hasAttribute('data-google-popup') || link.hasAttribute('data-auth-modal-open')) {
            return true;
        }

        const url = new URL(link.href, window.location.href);

        if (! ['http:', 'https:'].includes(url.protocol) || ! isEligibleUrl(url)) {
            return true;
        }

        return url.pathname === window.location.pathname
            && url.search === window.location.search
            && url.hash !== '';
    };

    const shouldShowLoaderFor = (url, options = {}) => {
        if (options.showLoader === false) {
            return false;
        }

        const nextUrl = new URL(url, window.location.href);

        return nextUrl.pathname !== window.location.pathname;
    };

    const shouldIgnoreForm = (event, form) => {
        if (event.defaultPrevented || ! form || form.target) {
            return true;
        }

        if (form.hasAttribute('data-no-pjax')
            || form.hasAttribute('data-save-job-form')
            || form.hasAttribute('data-resume-upload-form')
            || form.hasAttribute('data-auth-forgot-form')
            || form.hasAttribute('data-auth-reset-form')
            || form.enctype === 'multipart/form-data') {
            return true;
        }

        const url = new URL(form.action || window.location.href, window.location.href);

        return ! isEligibleUrl(url);
    };

    const executeScripts = (root) => {
        root.querySelectorAll('script').forEach((oldScript) => {
            const script = document.createElement('script');

            [...oldScript.attributes].forEach((attribute) => {
                script.setAttribute(attribute.name, attribute.value);
            });

            script.textContent = oldScript.textContent;
            oldScript.replaceWith(script);
        });
    };

    const replacePage = (html, responseUrl, shouldPushState = true) => {
        const documentFragment = new DOMParser().parseFromString(html, 'text/html');
        const nextRoot = documentFragment.querySelector(rootSelector);
        const currentRoot = document.querySelector(rootSelector);

        if (! nextRoot || ! currentRoot) {
            window.location.assign(responseUrl);

            return;
        }

        window.dispatchEvent(new CustomEvent('remotematch:before-page-swap'));

        document.title = documentFragment.title || document.title;
        document.documentElement.className = documentFragment.documentElement.className;
        document.body.className = documentFragment.body.className;
        document.body.classList.remove('overflow-hidden');

        currentRoot.replaceWith(nextRoot);
        executeScripts(nextRoot);
        initializePage();

        if (shouldPushState && responseUrl !== window.location.href) {
            window.history.pushState({ remoteMatchPjax: true }, '', responseUrl);
        }

        window.scrollTo({ top: 0, behavior: 'auto' });
    };

    const requestPage = async (url, options = {}) => {
        if (isNavigating) {
            return;
        }

        isNavigating = true;
        const showLoader = shouldShowLoaderFor(url, options);
        let loaderTimer = null;

        if (showLoader) {
            document.documentElement.classList.add('is-pjax-loading');
            loaderTimer = window.setTimeout(() => showPageLoader(), 120);
        }

        try {
            if ((options.method || 'GET').toUpperCase() !== 'GET') {
                pageCache.clear();
            }

            if ((options.method || 'GET').toUpperCase() === 'GET' && pageCache.has(url)) {
                replacePage(pageCache.get(url), url, options.pushState !== false);

                return;
            }

            const response = await fetch(url, {
                method: options.method || 'GET',
                body: options.body || null,
                credentials: 'same-origin',
                headers: {
                    'Accept': 'text/html, application/xhtml+xml',
                    'X-CSRF-TOKEN': csrfToken(),
                    'X-Requested-With': 'XMLHttpRequest',
                },
            });

            const contentType = response.headers.get('content-type') || '';

            if (! contentType.includes('text/html')) {
                window.location.assign(response.url || url);

                return;
            }

            const html = await response.text();

            if ((options.method || 'GET').toUpperCase() === 'GET') {
                pageCache.set(response.url || url, html);

                if (pageCache.size > 12) {
                    pageCache.delete(pageCache.keys().next().value);
                }
            }

            replacePage(html, response.url || url, options.pushState !== false);
        } catch {
            window.location.assign(url);
        } finally {
            isNavigating = false;

            if (loaderTimer) {
                window.clearTimeout(loaderTimer);
            }

            if (showLoader) {
                document.documentElement.classList.remove('is-pjax-loading');
                hidePageLoader();
            }
        }
    };

    const prefetchPage = (url) => {
        if (pageCache.has(url)) {
            return;
        }

        fetch(url, {
            method: 'GET',
            credentials: 'same-origin',
            headers: {
                'Accept': 'text/html, application/xhtml+xml',
                'X-Requested-With': 'XMLHttpRequest',
            },
        })
            .then((response) => {
                if (! response.ok || ! (response.headers.get('content-type') || '').includes('text/html')) {
                    return null;
                }

                return response.text();
            })
            .then((html) => {
                if (! html) {
                    return;
                }

                pageCache.set(url, html);

                if (pageCache.size > 12) {
                    pageCache.delete(pageCache.keys().next().value);
                }
            })
            .catch(() => {});
    };

    window.remoteMatchVisit = (url) => {
        const nextUrl = new URL(url, window.location.href);

        if (! isEligibleUrl(nextUrl)) {
            window.location.assign(nextUrl.toString());

            return;
        }

        requestPage(nextUrl.toString());
    };

    document.addEventListener('click', (event) => {
        const link = event.target.closest('a[href]');

        if (shouldIgnoreLink(event, link)) {
            return;
        }

        event.preventDefault();
        requestPage(new URL(link.href, window.location.href).toString());
    });

    document.addEventListener('pointerenter', (event) => {
        const link = event.target.closest('a[href]');

        if (! link || link.target || link.hasAttribute('data-no-pjax') || link.hasAttribute('data-google-popup') || link.hasAttribute('data-auth-modal-open')) {
            return;
        }

        const url = new URL(link.href, window.location.href);

        if (! isEligibleUrl(url) || url.pathname === window.location.pathname) {
            return;
        }

        prefetchPage(url.toString());
    }, true);

    document.addEventListener('submit', (event) => {
        const form = event.target;

        if (shouldIgnoreForm(event, form)) {
            return;
        }

        event.preventDefault();

        const method = (form.method || 'GET').toUpperCase();
        const url = new URL(form.action || window.location.href, window.location.href);

        if (method === 'GET') {
            const query = new URLSearchParams(new FormData(form));
            url.search = query.toString();
            requestPage(url.toString(), { showLoader: shouldShowLoaderFor(url.toString()) });

            return;
        }

        requestPage(url.toString(), {
            method: 'POST',
            body: new FormData(form),
        });
    });

    window.addEventListener('popstate', () => {
        requestPage(window.location.href, { pushState: false });
    });
};

window.addEventListener('message', (event) => {
    if (event.origin !== window.location.origin) {
        return;
    }

    if (event.data?.type === 'remotematch.google-auth.success' && event.data.nextUrl) {
        window.remoteMatchVisit ? window.remoteMatchVisit(event.data.nextUrl) : window.location.assign(event.data.nextUrl);
    }

    if (event.data?.type === 'remotematch.google-auth.failed' && event.data.nextUrl) {
        window.remoteMatchVisit ? window.remoteMatchVisit(event.data.nextUrl) : window.location.assign(event.data.nextUrl);
    }
});

if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => {
        initializePjax();
        initializePage();
    });
} else {
    initializePjax();
    initializePage();
}
