document.addEventListener('DOMContentLoaded', () => {
    initConditionalFields();
    initDependents();
    initMasks();
    initDataTable();
    initFilePreviews();
    initUpdateModal();
    initFormWizard();
    initUploadGuard();
    initFormTimeout();
    initSmartSubmit();
    scrollToFirstError();
});



function initFormWizard() {
    const form = document.querySelector('form[data-mobile-wizard="true"]');
    if (!form) return;

    const sections = Array.from(form.querySelectorAll('.form-section'));
    if (sections.length < 2) return;

    const finalActions = form.querySelector('.wizard-final-actions');
    const mobileQuery = window.matchMedia('(max-width: 991.98px)');
    let wizard = null;
    let currentStep = 0;

    const getSectionTitle = (section, index) => {
        const heading = section.querySelector('.section-header h2');
        if (!heading) return `Etapa ${index + 1}`;
        return heading.textContent.replace(/^\s*\d+[\.-]?\s*/, '').trim();
    };

    const sectionHasError = (section) => Boolean(section.querySelector('.is-invalid, .field-error'));

    const getInitialStep = () => {
        const invalidIndex = sections.findIndex(sectionHasError);
        return invalidIndex >= 0 ? invalidIndex : 0;
    };

    const focusActiveStep = () => {
        const activeSection = sections[currentStep];
        if (!activeSection) return;

        window.requestAnimationFrame(() => {
            activeSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
        });
    };

    const updateWizardUi = (shouldScroll = false) => {
        if (!wizard) return;

        sections.forEach((section, index) => {
            section.classList.add('wizard-step');
            section.classList.toggle('is-active', index === currentStep);
            if (index === currentStep) {
                section.removeAttribute('aria-hidden');
            } else {
                section.setAttribute('aria-hidden', 'true');
            }
        });

        const title = getSectionTitle(sections[currentStep], currentStep);
        const progress = ((currentStep + 1) / sections.length) * 100;
        const isLastStep = currentStep === sections.length - 1;

        wizard.stepCounter.textContent = `Etapa ${currentStep + 1} de ${sections.length}`;
        wizard.stepTitle.textContent = title;
        wizard.progressFill.style.width = `${progress}%`;
        wizard.prevButton.disabled = currentStep === 0;
        wizard.nav.hidden = isLastStep;

        if (finalActions) {
            finalActions.hidden = !isLastStep;
            finalActions.classList.toggle('is-active', isLastStep);
        }

        if (shouldScroll) {
            focusActiveStep();
        }
    };

    const setStep = (index, shouldScroll = true) => {
        currentStep = Math.max(0, Math.min(index, sections.length - 1));
        updateWizardUi(shouldScroll);
    };

    const enableWizard = () => {
        if (wizard) {
            updateWizardUi(false);
            return;
        }

        form.classList.add('mobile-wizard-enabled');

        const header = document.createElement('div');
        header.className = 'mobile-wizard-header';
        header.innerHTML = `
            <div class="mobile-wizard-header__meta">
                <span class="mobile-wizard-counter"></span>
                <strong class="mobile-wizard-title"></strong>
            </div>
            <div class="mobile-wizard-progress" aria-hidden="true">
                <span class="mobile-wizard-progress__fill"></span>
            </div>
        `;

        const nav = document.createElement('div');
        nav.className = 'mobile-wizard-nav';
        nav.innerHTML = `
            <button type="button" class="btn btn-outline-secondary mobile-wizard-prev">Voltar</button>
            <button type="button" class="btn btn-primary mobile-wizard-next">Próxima etapa</button>
        `;

        form.insertBefore(header, sections[0]);
        if (finalActions && finalActions.parentNode === form) {
            form.insertBefore(nav, finalActions);
        } else {
            form.appendChild(nav);
        }

        wizard = {
            header,
            nav,
            stepCounter: header.querySelector('.mobile-wizard-counter'),
            stepTitle: header.querySelector('.mobile-wizard-title'),
            progressFill: header.querySelector('.mobile-wizard-progress__fill'),
            prevButton: nav.querySelector('.mobile-wizard-prev'),
            nextButton: nav.querySelector('.mobile-wizard-next')
        };

        wizard.prevButton.addEventListener('click', () => setStep(currentStep - 1));
        wizard.nextButton.addEventListener('click', () => setStep(currentStep + 1));

        currentStep = getInitialStep();
        updateWizardUi(false);
    };

    const disableWizard = () => {
        form.classList.remove('mobile-wizard-enabled');
        sections.forEach((section) => {
            section.classList.remove('wizard-step', 'is-active');
            section.removeAttribute('aria-hidden');
        });

        if (finalActions) {
            finalActions.hidden = false;
            finalActions.classList.remove('is-active');
        }

        if (wizard) {
            wizard.header.remove();
            wizard.nav.remove();
            wizard = null;
        }
    };

    const syncWizardMode = () => {
        if (mobileQuery.matches) {
            enableWizard();
        } else {
            disableWizard();
        }
    };

    syncWizardMode();

    if (typeof mobileQuery.addEventListener === 'function') {
        mobileQuery.addEventListener('change', syncWizardMode);
    } else if (typeof mobileQuery.addListener === 'function') {
        mobileQuery.addListener(syncWizardMode);
    }
}



function renderFormAlert(form, type, storageClass, message, hint = '', shouldScroll = true) {
    let alert = form.querySelector(`.${storageClass}`);
    if (!alert) {
        alert = document.createElement('div');
        form.insertBefore(alert, form.firstChild);
    }

    alert.className = `alert alert-${type} shadow-sm form-alert ${storageClass}`;
    alert.innerHTML = `
        <strong>${escapeHtml(message)}</strong>
        ${hint ? `<div class="small mt-2">${escapeHtml(hint)}</div>` : ''}
    `;

    if (shouldScroll) {
        window.requestAnimationFrame(() => {
            alert.scrollIntoView({ behavior: 'smooth', block: 'start' });
        });
    }

    return alert;
}


function resetSubmitState(form) {
    if (!form) return;

    delete form.dataset.submitting;

    form.querySelectorAll('button[type="submit"], input[type="submit"]').forEach((button) => {
        button.disabled = false;
        button.classList.remove('is-submitting');

        if (button.tagName === 'BUTTON' && button.dataset.originalText) {
            button.innerHTML = button.dataset.originalText;
            delete button.dataset.originalText;
        }
    });
}

function initSmartSubmit() {
    document.querySelectorAll('form').forEach((form) => {
        form.addEventListener('submit', (event) => {
            if (event.defaultPrevented || form.dataset.submitting === '1' || form.dataset.formExpired === '1') {
                return;
            }

            window.setTimeout(() => {
                if (event.defaultPrevented || form.dataset.formExpired === '1') {
                    resetSubmitState(form);
                    return;
                }

                form.dataset.submitting = '1';

                form.querySelectorAll('button[type="submit"], input[type="submit"]').forEach((button) => {
                    button.disabled = true;
                    button.classList.add('is-submitting');
                    if (button.tagName === 'BUTTON' && !button.dataset.originalText) {
                        button.dataset.originalText = button.innerHTML;
                        button.innerHTML = 'Enviando...';
                    }
                });
            }, 0);
        });
    });
}

function initUploadGuard() {
    document.querySelectorAll('form[data-upload-guard="true"]').forEach((form) => {
        const maxFileSizeBytes = parseInt(form.dataset.maxFileSizeBytes || '0', 10);
        const maxFileSizeLabel = form.dataset.maxFileSizeLabel || '0 B';
        const postMaxBytes = parseInt(form.dataset.postMaxBytes || '0', 10);
        const postMaxLabel = form.dataset.postMaxLabel || '0 B';

        const renderError = (message) => renderFormAlert(
            form,
            'danger',
            'js-upload-error',
            message,
            'Revise o tipo e o tamanho do arquivo antes de tentar novamente.'
        );

        form.addEventListener('submit', (event) => {
            const previousError = form.querySelector('.js-upload-error');
            if (previousError) previousError.remove();

            const fileInputs = Array.from(form.querySelectorAll('input[type="file"]'));
            let totalSize = 0;
            let oversizedFile = null;

            fileInputs.forEach((input) => {
                Array.from(input.files || []).forEach((file) => {
                    totalSize += file.size || 0;
                    if (!oversizedFile && maxFileSizeBytes > 0 && (file.size || 0) > maxFileSizeBytes) {
                        oversizedFile = file;
                    }
                });
            });

            if (oversizedFile) {
                event.preventDefault();
                renderError(`O arquivo "${oversizedFile.name}" excede ${maxFileSizeLabel}. Reduza o tamanho e tente novamente.`);
                resetSubmitState(form);
                return;
            }

            if (postMaxBytes > 0 && totalSize > postMaxBytes) {
                event.preventDefault();
                renderError(`A soma dos anexos passou do limite total de ${postMaxLabel}. Reduza o tamanho dos arquivos e tente novamente.`);
                resetSubmitState(form);
            }
        });
    });
}


function initFormTimeout() {
    const form = document.querySelector('form[data-form-time-limit-seconds]');
    if (!form) return;

    const limitSeconds = parseInt(form.dataset.formTimeLimitSeconds || '0', 10);
    if (!Number.isFinite(limitSeconds) || limitSeconds <= 0) return;

    const storageKey = 'admission-form-timeout-message';
    const limitLabel = `${Math.ceil(limitSeconds / 60)} min`;
    const deadline = Date.now() + (limitSeconds * 1000);
    let timerId = null;
    let expired = false;

    const reloadCleanForm = () => {
        try {
            sessionStorage.setItem(storageKey, `O tempo máximo de ${limitLabel} foi atingido. A ficha foi reiniciada.`);
        } catch (error) {
            // ignore storage issues
        }

        try {
            form.reset();
            form.querySelectorAll('input[type="file"]').forEach((input) => {
                input.value = '';
            });
        } catch (error) {
            // ignore reset issues
        }

        const targetUrl = `${window.location.pathname}${window.location.search}`;
        window.setTimeout(() => {
            window.location.replace(targetUrl);
        }, 900);
    };

    const renderStoredMessage = () => {
        try {
            const message = sessionStorage.getItem(storageKey);
            if (!message) return;

            sessionStorage.removeItem(storageKey);
            renderFormAlert(form, 'warning', 'js-form-timeout-alert', message, 'Preencha novamente e envie dentro do prazo para evitar novo reset.');
        } catch (error) {
            // ignore storage issues
        }
    };

    const renderTimer = () => {
        const remainingSeconds = Math.max(0, Math.ceil((deadline - Date.now()) / 1000));
        const minutes = Math.floor(remainingSeconds / 60);
        const seconds = String(remainingSeconds % 60).padStart(2, '0');
        const statusClass = remainingSeconds <= 60 ? 'warning' : 'info';
        const existingAlert = form.querySelector('.js-form-deadline-alert');

        if (existingAlert) {
            existingAlert.className = `alert alert-${statusClass} shadow-sm form-alert js-form-deadline-alert`;
        }

        renderFormAlert(
            form,
            statusClass,
            'js-form-deadline-alert',
            `Tempo restante para envio: ${minutes}:${seconds}`,
            `Após ${limitLabel}, a página será recarregada e a ficha será limpa automaticamente.`,
            false
        );
    };

    const expireForm = () => {
        if (expired || form.dataset.submitting === '1') return;

        expired = true;
        form.dataset.formExpired = '1';
        if (timerId) {
            window.clearInterval(timerId);
        }

        renderFormAlert(
            form,
            'warning',
            'js-form-deadline-alert',
            `Tempo máximo de ${limitLabel} atingido.`,
            'A página será recarregada para reiniciar a ficha.'
        );
        reloadCleanForm();
    };

    form.addEventListener('submit', (event) => {
        if (expired) {
            event.preventDefault();
            resetSubmitState(form);
            return;
        }

        if (event.defaultPrevented) {
            resetSubmitState(form);
            return;
        }

        form.dataset.submitting = '1';
        if (timerId) {
            window.clearInterval(timerId);
        }
    });

    renderStoredMessage();
    renderTimer();

    timerId = window.setInterval(() => {
        if (form.dataset.submitting === '1') {
            window.clearInterval(timerId);
            return;
        }

        if (Date.now() >= deadline) {
            expireForm();
            return;
        }

        renderTimer();
    }, 1000);
}

function initUpdateModal() {
    const modalElement = document.getElementById('updateNoteModal');
    if (!modalElement || typeof window.bootstrap === 'undefined') return;

    const version = modalElement.dataset.updateVersion || '0';
    const storageKey = `update-note-dismissed-${version}`;
    const modal = new window.bootstrap.Modal(modalElement);
    const dismissButton = modalElement.querySelector('[data-update-dismiss]');

    const markDismissed = () => {
        try {
            localStorage.setItem(storageKey, '1');
        } catch (e) {
            // ignore storage issues
        }
        modal.hide();
    };

    if (dismissButton) {
        dismissButton.addEventListener('click', markDismissed);
    }

    modalElement.addEventListener('hidden.bs.modal', () => {
        try {
            localStorage.setItem(storageKey, '1');
        } catch (e) {
            // ignore storage issues
        }
    });

    let dismissed = false;
    try {
        dismissed = localStorage.getItem(storageKey) === '1';
    } catch (e) {
        dismissed = false;
    }

    if (!dismissed) {
        modal.show();
    }
}

function initConditionalFields() {
    document.querySelectorAll('.toggle-field').forEach((field) => {
        const updateState = () => {
            const target = document.querySelector(field.dataset.target);
            if (!target) return;
            target.classList.toggle('is-hidden', String(field.value) !== '1');
        };

        field.addEventListener('change', updateState);
        updateState();
    });

    const jobTitle = document.getElementById('job_title');
    const studentField = document.querySelector('[name="is_student"]');
    const maritalStatusField = document.getElementById('marital_status');
    const dependentsField = document.getElementById('has_dependents');
    const academicSection = document.getElementById('academic-section');
    const crefSection = document.getElementById('cref-section');
    const crefDocumentSection = document.getElementById('cref-document-section');
    const meiCertificateSection = document.getElementById('mei-certificate-section');
    const marriageCertificateSection = document.getElementById('marriage-certificate-section');
    const divorceAnnotationSection = document.getElementById('divorce-annotation-section');

    const normalize = (value) => {
        return String(value || '')
            .normalize('NFD')
            .replace(/[̀-ͯ]/g, '')
            .trim()
            .toLowerCase();
    };

    const syncJobSections = () => {
        const selectedJob = normalize(jobTitle ? jobTitle.value : '');
        const isStudent = studentField ? String(studentField.value || '0') === '1' : false;
        const isInternEdu = selectedJob === normalize('Estagiário Ed. Física');
        const isProfessorEdu =
            selectedJob === normalize('Professor de Musculação') ||
            selectedJob === normalize('Professor de natação') ||
            selectedJob.includes('professor');

        if (academicSection) {
            academicSection.classList.toggle('is-hidden', !(isStudent || isInternEdu));
        }

        if (crefSection) {
            crefSection.classList.toggle('is-hidden', !isProfessorEdu);
        }

        if (crefDocumentSection) {
            crefDocumentSection.classList.toggle('is-hidden', !isProfessorEdu);
        }

        if (meiCertificateSection) {
            meiCertificateSection.classList.toggle('is-hidden', !isProfessorEdu);
        }

        const maritalStatus = String(maritalStatusField ? maritalStatusField.value : '').trim().toLowerCase();
        const hasDependents = String(dependentsField ? dependentsField.value : '0') === '1';

        if (marriageCertificateSection) {
            marriageCertificateSection.classList.toggle('is-hidden', maritalStatus !== 'casado');
        }

        if (divorceAnnotationSection) {
            divorceAnnotationSection.classList.toggle('is-hidden', maritalStatus !== 'divorciado');
        }

    };

    if (jobTitle) {
        jobTitle.addEventListener('change', syncJobSections);
        jobTitle.addEventListener('input', syncJobSections);
    }

    if (studentField) {
        studentField.addEventListener('change', syncJobSections);
    }

    if (maritalStatusField) {
        maritalStatusField.addEventListener('change', syncJobSections);
    }

    if (dependentsField) {
        dependentsField.addEventListener('change', syncJobSections);
    }

    const bankPaymentMethodField = document.getElementById('bank_payment_method');
    const bankDetailsSection = document.getElementById('bank-details-section');
    const pixSection = document.getElementById('pix-section');

    const syncPaymentMethod = () => {
        const method = String(bankPaymentMethodField ? bankPaymentMethodField.value : 'bank');

        if (bankDetailsSection) {
            bankDetailsSection.classList.toggle('is-hidden', method !== 'bank');
        }

        if (pixSection) {
            pixSection.classList.toggle('is-hidden', method !== 'pix');
        }
    };

    if (bankPaymentMethodField) {
        bankPaymentMethodField.addEventListener('change', syncPaymentMethod);
        syncPaymentMethod();
    }

    syncJobSections();
}

function initDependents() {
    const wrapper = document.getElementById('dependents-wrapper');
    const addButton = document.getElementById('add-dependent');

    if (!wrapper || !addButton) return;

    const reindex = () => {
        [...wrapper.querySelectorAll('.dependent-card')].forEach((card, index) => {
            const title = card.querySelector('h3');
            if (title) title.textContent = `Dependente ${index + 1}`;

            card.querySelectorAll('input, select').forEach((input) => {
                const name = input.getAttribute('name');
                if (!name) return;

                let updatedName = name.replace(/dependents\[\d+\]/, `dependents[${index}]`);
                updatedName = updatedName.replace(/dependent_birth_certificates\[\d+\]/, `dependent_birth_certificates[${index}]`);
                input.setAttribute('name', updatedName);
            });
        });
    };

    addButton.addEventListener('click', () => {
        const newIndex = wrapper.querySelectorAll('.dependent-card').length;
        const card = document.createElement('div');

        card.className = 'dependent-card border rounded-4 p-3';
        card.innerHTML = `
            <div class="d-flex justify-content-between align-items-center mb-3">
                <h3 class="h6 mb-0">Dependente ${newIndex + 1}</h3>
                <button type="button" class="btn btn-sm btn-outline-danger remove-dependent">Remover</button>
            </div>
            <div class="row g-3">
                <div class="col-md-4">
                    <label class="form-label">Nome completo</label>
                    <input type="text" class="form-control" name="dependents[${newIndex}][full_name]">
                </div>
                <div class="col-md-3">
                    <label class="form-label">Data de nascimento</label>
                    <input type="date" class="form-control" name="dependents[${newIndex}][birth_date]">
                </div>
                <div class="col-md-3">
                    <label class="form-label">CPF</label>
                    <input type="text" class="form-control js-cpf" name="dependents[${newIndex}][cpf]">
                </div>
                <div class="col-md-2">
                    <label class="form-label">Deficiência?</label>
                    <select class="form-select" name="dependents[${newIndex}][has_disability]">
                        <option value="0">Não</option>
                        <option value="1">Sim</option>
                    </select>
                </div>
                <div class="col-md-6">
                    <label class="form-label">Local/cidade de nascimento</label>
                    <input type="text" class="form-control" name="dependents[${newIndex}][birth_city]">
                </div>
                <div class="col-md-6">
                    <label class="form-label">Certidão de nascimento do dependente ${newIndex + 1}</label>
                    <input type="file" class="form-control" name="dependent_birth_certificates[${newIndex}]" accept=".pdf">
                    <div class="form-text">Envie a certidão deste dependente.</div>
                </div>
            </div>
        `;

        wrapper.appendChild(card);
        initMasks();
        reindex();
    });

    wrapper.addEventListener('click', (event) => {
        const button = event.target.closest('.remove-dependent');
        if (!button) return;

        const card = button.closest('.dependent-card');
        if (card && wrapper.querySelectorAll('.dependent-card').length > 1) {
            card.remove();
            reindex();
        }
    });
}

function initMasks() {
    applyMask('.js-cpf', cpfMask, 'numeric');
    applyMask('.js-phone', phoneMask, 'tel');
    applyMask('.js-cep', cepMask, 'numeric');
    applyMask('.js-cnpj', cnpjMask, 'numeric');
    applyMoneyBehavior('.js-money');
}

function applyMask(selector, formatter, inputMode = null) {
    document.querySelectorAll(selector).forEach((input) => {
        input.removeEventListener('input', input._maskHandler || (() => { }));

        if (inputMode) {
            input.setAttribute('inputmode', inputMode);
        }

        const handler = () => {
            input.value = formatter(input.value);
        };

        input._maskHandler = handler;
        input.addEventListener('input', handler);
    });
}

function applyMoneyBehavior(selector) {
    document.querySelectorAll(selector).forEach((input) => {
        input.removeEventListener('input', input._moneyInputHandler || (() => { }));
        input.removeEventListener('blur', input._moneyBlurHandler || (() => { }));

        input.setAttribute('inputmode', 'decimal');
        if (!input.getAttribute('placeholder')) {
            input.setAttribute('placeholder', 'Ex.: 1500,00');
        }

        const inputHandler = () => {
            input.value = moneyTypingMask(input.value);
        };

        const blurHandler = () => {
            input.value = formatMoneyValue(input.value);
        };

        input._moneyInputHandler = inputHandler;
        input._moneyBlurHandler = blurHandler;

        input.addEventListener('input', inputHandler);
        input.addEventListener('blur', blurHandler);
    });
}

function formatFileSize(bytes) {
    const size = Number(bytes || 0);

    if (!Number.isFinite(size) || size <= 0) {
        return '0 B';
    }

    const units = ['B', 'KB', 'MB', 'GB', 'TB'];
    let value = size;
    let unitIndex = 0;

    while (value >= 1024 && unitIndex < units.length - 1) {
        value /= 1024;
        unitIndex += 1;
    }

    const decimals = value >= 100 || unitIndex === 0 ? 0 : (value >= 10 ? 1 : 2);
    return `${value.toLocaleString('pt-BR', {
        minimumFractionDigits: decimals,
        maximumFractionDigits: decimals,
    })} ${units[unitIndex]}`;
}

function initFilePreviews() {
    document.querySelectorAll('.js-file-preview').forEach((input) => {
        const wrapper = document.querySelector(input.dataset.previewTarget);
        const image = document.querySelector(input.dataset.previewImage);
        const meta = document.querySelector(input.dataset.previewMeta);

        if (!wrapper || !image || !meta) return;

        input.addEventListener('change', () => {
            const file = input.files && input.files[0] ? input.files[0] : null;
            const media = wrapper.querySelector('.upload-preview__media');
            const accept = (input.getAttribute('accept') || '').toLowerCase();
            const acceptsImage = accept.includes('.jpg') || accept.includes('.jpeg') || accept.includes('.png');
            const acceptsPdf = accept.includes('.pdf');
            const fileName = file ? String(file.name || '').toLowerCase() : '';
            const isPdf = file && (file.type === 'application/pdf' || fileName.endsWith('.pdf'));
            const isImage = file && (
                String(file.type || '').startsWith('image/') ||
                fileName.endsWith('.jpg') ||
                fileName.endsWith('.jpeg') ||
                fileName.endsWith('.png')
            );

            if (!file) {
                wrapper.classList.add('is-empty');
                if (media) media.classList.add('d-none');
                image.removeAttribute('src');
                meta.innerHTML = `
                    <div class="upload-preview__filename">Nenhum arquivo selecionado</div>
                    <div class="upload-preview__hint">${acceptsImage ? 'A miniatura aparece aqui quando você escolher uma imagem.' : 'Selecione um arquivo PDF.'}</div>
                `;
                return;
            }

            if ((acceptsPdf && !acceptsImage && !isPdf) || (acceptsImage && !acceptsPdf && !isImage)) {
                input.value = '';
                wrapper.classList.add('is-empty');
                if (media) media.classList.add('d-none');
                image.removeAttribute('src');
                meta.innerHTML = `
                    <div class="upload-preview__filename">Arquivo não aceito</div>
                    <div class="upload-preview__hint">${acceptsImage ? 'Envie uma imagem JPG ou PNG.' : 'Envie um arquivo PDF.'}</div>
                `;
                return;
            }

            wrapper.classList.remove('is-empty');

            if (isImage) {
                const objectUrl = URL.createObjectURL(file);

                image.src = objectUrl;
                if (media) media.classList.remove('d-none');

                meta.innerHTML = `
                    <div class="upload-preview__filename">${escapeHtml(file.name)}</div>
                    <div class="upload-preview__size">Tamanho: ${escapeHtml(formatFileSize(file.size))}</div>
                    <div class="upload-preview__hint">Pré-visualização da imagem selecionada</div>
                `;

                image.onload = () => URL.revokeObjectURL(objectUrl);
                return;
            }

            if (media) media.classList.add('d-none');
            image.removeAttribute('src');

            meta.innerHTML = `
                <div class="upload-preview__filename">${escapeHtml(file.name)}</div>
                <div class="upload-preview__size">Tamanho: ${escapeHtml(formatFileSize(file.size))}</div>
                <div class="upload-preview__hint">Arquivo selecionado. Prévia visual disponível apenas para imagens.</div>
            `;
        });
    });
}

function onlyDigits(v) {
    return v.replace(/\D/g, '');
}

function cpfMask(v) {
    v = onlyDigits(v).slice(0, 11);
    v = v.replace(/(\d{3})(\d)/, '$1.$2');
    v = v.replace(/(\d{3})(\d)/, '$1.$2');
    return v.replace(/(\d{3})(\d{1,2})$/, '$1-$2');
}

function phoneMask(v) {
    v = onlyDigits(v).slice(0, 11);

    if (v.length <= 10) {
        v = v.replace(/(\d{2})(\d)/, '($1) $2');
        return v.replace(/(\d{4})(\d)/, '$1-$2');
    }

    v = v.replace(/(\d{2})(\d)/, '($1) $2');
    return v.replace(/(\d{5})(\d)/, '$1-$2');
}

function cepMask(v) {
    v = onlyDigits(v).slice(0, 8);
    return v.replace(/(\d{5})(\d)/, '$1-$2');
}

function cnpjMask(v) {
    v = onlyDigits(v).slice(0, 14);
    v = v.replace(/^(\d{2})(\d)/, '$1.$2');
    v = v.replace(/^(\d{2})\.(\d{3})(\d)/, '$1.$2.$3');
    v = v.replace(/\.(\d{3})(\d)/, '.$1/$2');
    return v.replace(/(\d{4})(\d)/, '$1-$2');
}

function moneyTypingMask(v) {
    v = String(v || '').replace(/[^\d,\.]/g, '');

    const lastComma = v.lastIndexOf(',');
    const lastDot = v.lastIndexOf('.');
    const separatorIndex = Math.max(lastComma, lastDot);

    if (separatorIndex === -1) {
        return v.replace(/[^\d]/g, '');
    }

    const integerPart = v.slice(0, separatorIndex).replace(/[^\d]/g, '');
    const decimalPart = v.slice(separatorIndex + 1).replace(/[^\d]/g, '').slice(0, 2);

    return `${integerPart},${decimalPart}`;
}

function formatMoneyValue(v) {
    const typedValue = moneyTypingMask(v);
    if (!typedValue) return '';

    const normalized = typedValue.replace(',', '.');
    const number = parseFloat(normalized);
    if (Number.isNaN(number)) return '';

    return number.toFixed(2).replace('.', ',');
}

function initDataTable() {
    const table = document.getElementById('admissions-table');
    if (!table || typeof window.DataTable === 'undefined') return;

    const tbody = table.querySelector('tbody');
    const headerCells = table.querySelectorAll('thead th').length;
    const rows = tbody ? Array.from(tbody.querySelectorAll('tr')) : [];

    if (!rows.length) return;

    const invalidRow = rows.some((row) => row.children.length !== headerCells);
    if (invalidRow) return;

    new DataTable(table, {
        language: {
            search: 'Filtrar resultados:',
            lengthMenu: 'Mostrar _MENU_ registros',
            info: 'Mostrando _START_ a _END_ de _TOTAL_ registros',
            paginate: {
                first: 'Primeira',
                last: 'Última',
                next: 'Próxima',
                previous: 'Anterior'
            },
            zeroRecords: 'Nenhum resultado encontrado',
            infoEmpty: 'Nenhum registro disponível',
            infoFiltered: '(filtrado de _MAX_ registros)'
        },
        order: [[0, 'desc']],
        pageLength: 10,
        deferRender: true,
        stateSave: true
    });
}

function escapeHtml(value) {
    const map = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };

    return String(value).replace(/[&<>"']/g, (m) => map[m]);
}

function scrollToFirstError() {
    const firstInvalid = document.querySelector('.is-invalid, .field-error');
    if (!firstInvalid) return;

    const target = firstInvalid.classList.contains('field-error')
        ? firstInvalid.previousElementSibling || firstInvalid
        : firstInvalid;

    window.requestAnimationFrame(() => {
        target.scrollIntoView({ behavior: 'smooth', block: 'center' });
        if (typeof target.focus === 'function') {
            target.focus({ preventScroll: true });
        }
    });
}
