// ── Registration & Passwords (Settings) ─────────────────────────────────────
// Every control here is enforced by the GENERATED app: the values travel into
// the build as the auth policy and are applied by core/Auth/AuthGuard.
// The password tester at the bottom runs the same rules the server applies.

const SECREG_DEFAULTS = {
    allow_registration: false,
    require_username: true,
    require_email: true,
    require_fullname: false,
    default_role: 'user',
    email_domain_mode: 'any',
    email_domains: '',
    bot_trap: true,
    min_fill_seconds: 2,
    enable_password_reset: true,
    activation_mode: 'none',
    activation_hours: 24,
    admin_email: '',
    password_policy: {
        min_length: 8, max_length: 200,
        require_numbers: false, require_mixed_case: false, require_special: false,
        block_common: true, block_identity: true, hash_algorithm: 'bcrypt'
    },
    password_reset: { token_expiry_hours: 24 }
};

// Kept in step with AuthGuard::COMMON — enough to demonstrate the rule here.
const SECREG_COMMON = ['password','passw0rd','password1','password123','123456','12345678','123456789',
    '1234567890','qwerty','qwerty123','abc123','111111','000000','iloveyou','admin','admin123',
    'administrator','welcome','welcome1','letmein','monkey','dragon','sunshine','princess','football',
    'baseball','master','shadow','superman','trustno1','changeme','secret','pass123','test123','root',
    'login','guest','user','default','starwars','whatever'];

async function renderRegistrationSettings() {
    const container = document.getElementById('securityPageContainer');
    container.innerHTML = '<div class="text-center py-5"><div class="spinner-border"></div></div>';

    let cfg = JSON.parse(JSON.stringify(SECREG_DEFAULTS));
    try {
        const res = await fetch(`${baseUrl}/project/${projectSlug}/security/registration`);
        const data = await res.json();
        if (!data.success) throw new Error(data.message || 'Unable to load settings.');
        cfg = {
            ...cfg, ...data.settings,
            password_policy: { ...cfg.password_policy, ...(data.settings.password_policy || {}) },
            password_reset:  { ...cfg.password_reset,  ...(data.settings.password_reset  || {}) }
        };
    } catch (e) {
        container.innerHTML = `<div class="secdb-empty"><i class="bi bi-exclamation-triangle"></i>
            <strong>Could not load registration settings</strong><span>${escapeHtml(e.message)}</span></div>`;
        return;
    }
    window.updateSecurityChrome?.('settings-registration');

    // `path` is either "key" or "password_policy.key"
    const val = p => p.includes('.') ? cfg[p.split('.')[0]][p.split('.')[1]] : cfg[p];
    const setVal = (p, v) => { p.includes('.') ? (cfg[p.split('.')[0]][p.split('.')[1]] = v) : (cfg[p] = v); };

    const toggle = (p, title, hint) => `
        <div class="seclg-row">
            <div class="seclg-row-copy"><strong>${title}</strong><span>${hint}</span></div>
            <div class="form-check form-switch m-0">
                <input class="form-check-input" type="checkbox" role="switch" data-cfg="${p}" ${val(p) ? 'checked' : ''}>
            </div>
        </div>`;

    const num = (p, title, hint, min, max, suffix) => `
        <div class="seclg-row">
            <div class="seclg-row-copy"><strong>${title}</strong><span>${hint}</span></div>
            <div class="seclg-range" style="max-width:160px">
                <input type="number" class="form-control form-control-sm" min="${min}" max="${max}"
                       value="${val(p)}" data-cfg="${p}">
                <output style="min-width:auto">${suffix}</output>
            </div>
        </div>`;

    const text = (p, title, hint, placeholder) => `
        <div class="seclg-row">
            <div class="seclg-row-copy"><strong>${title}</strong><span>${hint}</span></div>
            <input class="form-control form-control-sm" style="max-width:230px" data-cfg="${p}"
                   value="${escapeHtml(val(p) ?? '')}" placeholder="${escapeHtml(placeholder || '')}" spellcheck="false">
        </div>`;

    container.innerHTML = `
        <div class="secdb" style="gap:12px">
            <div class="secdb-master ${cfg.allow_registration ? 'is-on' : ''}" id="secregMaster">
                <span class="secdb-master-icon"><i class="bi bi-person-plus"></i></span>
                <div class="secdb-master-copy">
                    <strong>Public sign-up</strong>
                    <p>When this is off the generated app refuses sign-ups outright — the form is not merely hidden.</p>
                </div>
                <label class="secdb-switch form-switch" for="secregAllow">
                    <span class="secdb-switch-state" id="secregState">${cfg.allow_registration ? 'Open' : 'Closed'}</span>
                    <input class="form-check-input" type="checkbox" role="switch" id="secregAllow"
                           data-cfg="allow_registration" ${cfg.allow_registration ? 'checked' : ''}>
                </label>
            </div>

            <div id="secregBody" class="secdb" style="gap:12px">
                <div class="secdb-panel">
                    <div class="secdb-panel-head"><i class="bi bi-input-cursor-text"></i>
                        <div><h6>Sign-up form</h6><small>What a new account must provide</small></div></div>
                    <div class="secdb-panel-body" style="padding-block:6px">
                        ${toggle('require_username', 'Username required', 'Rejected server-side when empty')}
                        ${toggle('require_email', 'Email required', 'Also validated as a real address')}
                        ${toggle('require_fullname', 'Full name required', 'Useful for staff-facing apps')}
                        ${text('default_role', 'Role for new accounts', 'Never use an administrator role here', 'user')}
                    </div>
                </div>

                <div class="secdb-panel">
                    <div class="secdb-panel-head"><i class="bi bi-envelope-at"></i>
                        <div><h6>Who may sign up</h6><small>Restrict by email domain</small></div></div>
                    <div class="secdb-panel-body" style="padding-block:6px">
                        <div class="seclg-row">
                            <div class="seclg-row-copy"><strong>Domain rule</strong><span>Applies to the email address</span></div>
                            <select class="form-select form-select-sm" style="max-width:230px" data-cfg="email_domain_mode">
                                <option value="any"   ${cfg.email_domain_mode === 'any'   ? 'selected' : ''}>Any domain</option>
                                <option value="allow" ${cfg.email_domain_mode === 'allow' ? 'selected' : ''}>Only these domains</option>
                                <option value="block" ${cfg.email_domain_mode === 'block' ? 'selected' : ''}>Everything except these</option>
                            </select>
                        </div>
                        <div id="secregDomains" style="${cfg.email_domain_mode === 'any' ? 'display:none' : ''}">
                            ${text('email_domains', 'Domains', 'Comma separated. Subdomains are included.', 'corp.com, partner.org')}
                        </div>
                    </div>
                </div>

                <div class="secdb-panel">
                    <div class="secdb-panel-head"><i class="bi bi-patch-check"></i>
                        <div><h6>Account activation</h6><small>Whether a new account can sign in straight away</small></div></div>
                    <div class="secdb-panel-body" style="padding-block:6px">
                        <div class="seclg-row">
                            <div class="seclg-row-copy"><strong>Activation</strong><span>New accounts are created as “pending” unless this is off</span></div>
                            <select class="form-select form-select-sm" style="max-width:230px" data-cfg="activation_mode">
                                <option value="none"  ${cfg.activation_mode === 'none'  ? 'selected' : ''}>Active immediately</option>
                                <option value="email" ${cfg.activation_mode === 'email' ? 'selected' : ''}>Confirm email address</option>
                                <option value="admin" ${cfg.activation_mode === 'admin' ? 'selected' : ''}>Administrator approval</option>
                            </select>
                        </div>
                        <div id="secregActEmail" style="${cfg.activation_mode === 'email' ? '' : 'display:none'}">
                            ${num('activation_hours', 'Confirmation link lifetime', 'How long the link stays valid', 1, 720, 'hrs')}
                        </div>
                        <div id="secregActAdmin" style="${cfg.activation_mode === 'admin' ? '' : 'display:none'}">
                            ${text('admin_email', 'Notify this address', 'Where the “someone is waiting” email goes', 'admin@example.com')}
                        </div>
                    </div>
                </div>

                <div class="secdb-panel">
                    <div class="secdb-panel-head"><i class="bi bi-robot"></i>
                        <div><h6>Bot defence</h6><small>No third-party CAPTCHA needed</small></div></div>
                    <div class="secdb-panel-body" style="padding-block:6px">
                        ${toggle('bot_trap', 'Hidden field + timing trap', 'A field humans never see, plus a minimum time on the page')}
                        ${num('min_fill_seconds', 'Minimum fill time', 'Faster than this is treated as a script', 0, 60, 'sec')}
                    </div>
                </div>
            </div>

            <div class="secdb-panel">
                <div class="secdb-panel-head"><i class="bi bi-key"></i>
                    <div><h6>Password rules</h6><small>Enforced on sign-up and on password reset</small></div></div>
                <div class="secdb-panel-body" style="padding-block:6px">
                    ${num('password_policy.min_length', 'Minimum length', 'Characters required', 4, 128, 'chars')}
                    ${num('password_policy.max_length', 'Maximum length', 'bcrypt only reads the first 72 bytes', 20, 4096, 'chars')}
                    ${toggle('password_policy.require_numbers', 'Require a number', 'At least one digit')}
                    ${toggle('password_policy.require_mixed_case', 'Require mixed case', 'Upper and lower case letters')}
                    ${toggle('password_policy.require_special', 'Require a symbol', 'Any non-alphanumeric character')}
                    ${toggle('password_policy.block_common', 'Block common passwords', 'Rejects the usual credential-stuffing list')}
                    ${toggle('password_policy.block_identity', 'Block name/email in password', 'Stops “prakash2024” for user prakash')}
                </div>
            </div>

            <div class="secdb-panel">
                <div class="secdb-panel-head"><i class="bi bi-arrow-counterclockwise"></i>
                    <div><h6>Password reset</h6><small>The forgot-password flow</small></div></div>
                <div class="secdb-panel-body" style="padding-block:6px">
                    ${toggle('enable_password_reset', 'Allow password reset', 'Turning this off disables the flow server-side')}
                    ${num('password_reset.token_expiry_hours', 'Link lifetime', 'How long a reset link stays valid', 1, 720, 'hrs')}
                    <div class="seclg-row">
                        <div class="seclg-row-copy"><strong>Always applied</strong><span>Not configurable, because weakening them would be a bug</span></div>
                        <div class="secdb-summary" style="justify-content:flex-end">
                            <span class="secdb-pill is-ok"><i class="bi bi-check2"></i> Single-use links</span>
                            <span class="secdb-pill is-ok"><i class="bi bi-check2"></i> Kills “remember me” tokens</span>
                            <span class="secdb-pill is-ok"><i class="bi bi-check2"></i> No account disclosure</span>
                        </div>
                    </div>
                </div>
            </div>

            <div class="secdb-panel">
                <div class="secdb-panel-head"><i class="bi bi-shield-check"></i>
                    <div><h6>Try a password</h6><small>Runs the rules above, exactly as the app does</small></div></div>
                <div class="secdb-panel-body secdb" style="gap:9px">
                    <div class="secdb-grid2">
                        <div class="secdb-field">
                            <label class="secdb-label" for="secregTestPw">Password</label>
                            <input class="form-control form-control-sm" id="secregTestPw" placeholder="type to test…" autocomplete="off">
                        </div>
                        <div class="secdb-field">
                            <label class="secdb-label" for="secregTestUser">As username (optional)</label>
                            <input class="form-control form-control-sm" id="secregTestUser" placeholder="e.g. prakash" autocomplete="off">
                        </div>
                    </div>
                    <div class="secdb-summary" id="secregTestOut"></div>
                </div>
            </div>

            <div class="secdb-foot">
                <div class="secdb-summary" id="secregSummary"></div>
                <button class="btn btn-primary btn-sm" id="btnSaveRegSettings"><i class="bi bi-save me-1"></i> Save settings</button>
            </div>
        </div>
    `;

    // ── the same checks AuthGuard applies, for the live tester ──────────
    function problems(pw, username) {
        const p = cfg.password_policy, out = [];
        if (pw.length < p.min_length) out.push(`be at least ${p.min_length} characters long`);
        if (pw.length > p.max_length) out.push(`be no longer than ${p.max_length} characters`);
        if (p.require_numbers && !/\d/.test(pw)) out.push('include a number');
        if (p.require_mixed_case && !(/[a-z]/.test(pw) && /[A-Z]/.test(pw))) out.push('include both upper and lower case letters');
        if (p.require_special && !/[^A-Za-z0-9]/.test(pw)) out.push('include a symbol');
        if (p.block_common) {
            const low = pw.toLowerCase();
            const stripped = low.replace(/[0-9!@#$%^&*]+$/, '');
            if (SECREG_COMMON.includes(low) || SECREG_COMMON.includes(stripped)) out.push('not be a common password');
        }
        if (p.block_identity && username) {
            const bits = username.toLowerCase().split(/[\s._-]+/).filter(b => b.length >= 4);
            if (bits.some(b => pw.toLowerCase().includes(b))) out.push('not contain your name or email address');
        }
        return out;
    }

    function refresh() {
        const open = !!cfg.allow_registration;
        document.getElementById('secregMaster').classList.toggle('is-on', open);
        document.getElementById('secregState').textContent = open ? 'Open' : 'Closed';
        document.getElementById('secregBody').style.display = open ? '' : 'none';
        document.getElementById('secregDomains').style.display = cfg.email_domain_mode === 'any' ? 'none' : '';
        document.getElementById('secregActEmail').style.display = cfg.activation_mode === 'email' ? '' : 'none';
        document.getElementById('secregActAdmin').style.display = cfg.activation_mode === 'admin' ? '' : 'none';

        const p = cfg.password_policy;
        const bits = [`${p.min_length}+ chars`];
        if (p.require_numbers) bits.push('number');
        if (p.require_mixed_case) bits.push('mixed case');
        if (p.require_special) bits.push('symbol');
        if (p.block_common) bits.push('no common');
        if (p.block_identity) bits.push('no identity');
        document.getElementById('secregSummary').innerHTML =
            `<span class="secdb-pill ${open ? 'is-warn' : 'is-ok'}"><i class="bi bi-person-plus"></i> Sign-up ${open ? 'open to the public' : 'closed'}</span>`
            + `<span class="secdb-pill is-ok"><i class="bi bi-key"></i> ${bits.join(' · ')}</span>`
            + (cfg.activation_mode !== 'none'
                ? `<span class="secdb-pill"><i class="bi bi-patch-check"></i> ${cfg.activation_mode === 'email' ? 'Email confirmation' : 'Admin approval'} required</span>`
                : '');
        test();
    }

    function test() {
        const pw = document.getElementById('secregTestPw').value;
        const user = document.getElementById('secregTestUser').value.trim();
        const out = document.getElementById('secregTestOut');
        if (!pw) { out.innerHTML = '<span class="secdb-pill"><i class="bi bi-dash-circle"></i> Enter a password to check it</span>'; return; }
        const probs = problems(pw, user);
        out.innerHTML = probs.length
            ? `<span class="secdb-pill is-warn"><i class="bi bi-x-circle"></i> Rejected — must ${probs.join(', ')}</span>`
            : '<span class="secdb-pill is-ok"><i class="bi bi-check-circle"></i> Accepted by these rules</span>';
    }

    container.querySelectorAll('[data-cfg]').forEach(el => {
        const p = el.getAttribute('data-cfg');
        el.addEventListener(el.type === 'checkbox' || el.tagName === 'SELECT' ? 'change' : 'input', () => {
            if (el.type === 'checkbox') setVal(p, el.checked);
            else if (el.type === 'number') setVal(p, parseInt(el.value, 10) || 0);
            else setVal(p, el.value);
            refresh();
        });
    });
    ['secregTestPw', 'secregTestUser'].forEach(id =>
        document.getElementById(id).addEventListener('input', test));

    document.getElementById('btnSaveRegSettings').addEventListener('click', async () => {
        try {
            const res = await fetch(`${baseUrl}/project/${projectSlug}/security/registration`, {
                method: 'POST', headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ settings: cfg })
            });
            const data = await res.json();
            if (!data.success) return pp.dialog.alert('Error', data.message, 'error');
            pp.dialog.toast('success', 'Registration settings saved. Rebuild to publish them.');
            if (data.settings) {                     // reflect the server-clamped values
                cfg = { ...cfg, ...data.settings,
                    password_policy: { ...cfg.password_policy, ...(data.settings.password_policy || {}) },
                    password_reset:  { ...cfg.password_reset,  ...(data.settings.password_reset  || {}) } };
                refresh();
                container.querySelectorAll('[data-cfg]').forEach(el => {
                    const p = el.getAttribute('data-cfg');
                    if (el.type === 'checkbox') el.checked = !!val(p); else el.value = val(p) ?? '';
                });
            }
        } catch (e) { pp.dialog.toast('error', 'Network error'); }
    });

    refresh();
    // No auto-save: these are security rules, changed deliberately.
}

window.renderRegistrationSettings = renderRegistrationSettings;
