function esc(s) {
    const d = document.createElement('div');
    d.textContent = s ?? '';
    return d.innerHTML;
}

function formatMessageHTML(message) {
    return String(message)
        .split(/\n\n+/)
        .map((block) => `<p>${esc(block).replace(/\n/g, '<br>')}</p>`)
        .join('');
}

function renderChoicesHTML(choices) {
    const name = 'confirm_modal_choice';
    return `
        <fieldset class="password-mode-fieldset confirm-modal-choices">
            <div class="password-mode-options">
                ${choices.map((choice, i) => `
                    <label class="password-mode-option">
                        <input type="radio" name="${name}" value="${esc(choice.value)}"${i === 0 ? ' checked' : ''}>
                        <span class="password-mode-option-title">${esc(choice.label)}</span>
                        ${choice.description
                            ? `<span class="password-mode-option-desc">${esc(choice.description)}</span>`
                            : ''}
                    </label>
                `).join('')}
            </div>
        </fieldset>`;
}

/** @type {((value: boolean | string | null) => void) | null} */
let resolveConfirm = null;

function ensureConfirmModal() {
    let modal = document.getElementById('confirmModal');
    if (modal) return modal;

    modal = document.createElement('div');
    modal.id = 'confirmModal';
    modal.className = 'modal-overlay';
    modal.hidden = true;
    modal.setAttribute('role', 'dialog');
    modal.setAttribute('aria-modal', 'true');
    modal.setAttribute('aria-labelledby', 'confirmModalTitle');
    modal.innerHTML = `
        <div class="modal-dialog confirm-modal-dialog">
            <h2 id="confirmModalTitle"></h2>
            <div class="confirm-modal-message modal-subtitle" id="confirmModalMessage"></div>
            <div id="confirmModalChoices"></div>
            <div class="modal-actions">
                <button type="button" class="btn btn-sm" data-confirm-cancel>Cancel</button>
                <button type="button" class="btn btn-sm btn-primary" data-confirm-submit>Confirm</button>
            </div>
        </div>
    `;
    document.body.appendChild(modal);

    modal.addEventListener('click', (e) => {
        if (e.target === modal) finishConfirm(null);
    });
    modal.querySelector('[data-confirm-cancel]').addEventListener('click', () => finishConfirm(null));
    modal.querySelector('[data-confirm-submit]').addEventListener('click', () => {
        const choicesEl = modal.querySelector('#confirmModalChoices');
        const hasChoices = choicesEl.childElementCount > 0;
        if (hasChoices) {
            const selected = modal.querySelector('input[name="confirm_modal_choice"]:checked');
            finishConfirm(selected ? selected.value : null);
        } else {
            finishConfirm(true);
        }
    });

    document.addEventListener('keydown', (e) => {
        const el = document.getElementById('confirmModal');
        if (!el || el.hidden) return;
        if (e.key === 'Escape') finishConfirm(null);
    });

    return modal;
}

function finishConfirm(value) {
    const modal = document.getElementById('confirmModal');
    if (!modal || modal.hidden) return;
    modal.hidden = true;
    document.body.classList.remove('modal-open');
    const resolve = resolveConfirm;
    resolveConfirm = null;
    if (resolve) resolve(value);
}

/**
 * Show a confirmation dialog.
 *
 * Without `choices`: resolves to `true` (confirmed) or `false` (cancelled).
 * With `choices`: resolves to the selected choice value (string) or `null` (cancelled).
 *
 * @param {Object} options
 * @param {string} options.title
 * @param {string} options.message
 * @param {string} [options.confirmLabel='Confirm']
 * @param {string} [options.cancelLabel='Cancel']
 * @param {'default'|'danger'} [options.variant='default']
 * @param {{ value: string, label: string, description?: string }[]} [options.choices]
 * @returns {Promise<boolean|string|null>}
 */
export function confirmAction(options) {
    return new Promise((resolve) => {
        if (resolveConfirm) {
            resolve(false);
            return;
        }

        const modal = ensureConfirmModal();
        const hasChoices = Array.isArray(options.choices) && options.choices.length > 0;
        const variant = options.variant === 'danger' ? 'danger' : 'default';

        modal.querySelector('#confirmModalTitle').textContent = options.title || 'Confirm';
        modal.querySelector('#confirmModalMessage').innerHTML = formatMessageHTML(options.message || '');

        const choicesEl = modal.querySelector('#confirmModalChoices');
        choicesEl.innerHTML = hasChoices ? renderChoicesHTML(options.choices) : '';

        const cancelBtn = modal.querySelector('[data-confirm-cancel]');
        const submitBtn = modal.querySelector('[data-confirm-submit]');
        cancelBtn.textContent = options.cancelLabel || 'Cancel';
        submitBtn.textContent = options.confirmLabel || (hasChoices ? 'Continue' : 'Confirm');
        submitBtn.className = `btn btn-sm ${variant === 'danger' ? 'btn-danger' : 'btn-primary'}`;

        modal.classList.toggle('confirm-modal--danger', variant === 'danger');

        resolveConfirm = (value) => {
            if (hasChoices) {
                resolve(value);
            } else {
                resolve(value === true);
            }
        };

        modal.hidden = false;
        document.body.classList.add('modal-open');
        (hasChoices
            ? modal.querySelector('input[name="confirm_modal_choice"]')
            : submitBtn
        )?.focus();
    });
}
