// ==========================================
// Policy Gating & UI Logic Tests
// ==========================================
// Validates that admin policies correctly
// gate user-facing features. These catch
// the exact class of bugs where a backend
// policy exists but the frontend doesn't
// check it.
//
// v0.22.5: Updated for server-rendered Go templates.
// v0.37.5: Settings surface moved to Preact — legacy SPA tests
//          replaced with component source audits.
// v0.37.10: Legacy SPA source audit removed (ui-core.js, app.js,
//           pages.js, settings-handlers.js, ui-admin.js all deleted).
//           Policy gating now verified via Preact surfaces + admin templates.
// v0.37.12: Admin Go templates deleted (Preact since v0.37.6). Template
//           element ID assertions removed — Preact component source audits
//           at the bottom of this file cover the same policy keys.
//
// Run: node --test src/js/__tests__/policy-gating.test.js
// ==========================================

const { describe, it } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');

const SRC = path.join(__dirname, '..');
const TEMPLATES = path.join(__dirname, '..', '..', '..', 'server', 'pages', 'templates');

// ── Helper: read all server template HTML ────
function readAllTemplates() {
    const files = [];
    function walk(dir) {
        for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
            const full = path.join(dir, entry.name);
            if (entry.isDirectory()) walk(full);
            else if (entry.name.endsWith('.html')) files.push(fs.readFileSync(full, 'utf-8'));
        }
    }
    walk(TEMPLATES);
    return files.join('\n');
}

// ── Policy evaluation logic ──────────────────

describe('Policy evaluation logic', () => {
    function isPolicyEnabled(policies, key) {
        return policies?.[key] === 'true';
    }

    it('policy "true" (string) → enabled', () => {
        assert.equal(isPolicyEnabled({ allow_user_byok: 'true' }, 'allow_user_byok'), true);
    });

    it('policy "false" (string) → disabled', () => {
        assert.equal(isPolicyEnabled({ allow_user_byok: 'false' }, 'allow_user_byok'), false);
    });

    it('policy boolean true → NOT enabled (must be string)', () => {
        assert.equal(isPolicyEnabled({ allow_user_byok: true }, 'allow_user_byok'), false,
            'DANGER: policies are string "true"/"false", not boolean');
    });

    it('missing policy → disabled', () => {
        assert.equal(isPolicyEnabled({}, 'allow_user_byok'), false);
    });

    it('null policies → disabled', () => {
        assert.equal(isPolicyEnabled(null, 'allow_user_byok'), false);
    });

    it('undefined policies → disabled', () => {
        assert.equal(isPolicyEnabled(undefined, 'allow_user_byok'), false);
    });
});

// ── Team member dropdown logic ───────────────

describe('Team member dropdown population', () => {
    // admin/users returns {data:[...], total:N} — has siblings, _unwrap passes through.
    // teams/members returns {data:[...]} — sole key, _unwrap strips to bare array.
    function getAvailableUsers(usersResp, membersArr) {
        const users = usersResp.data || [];
        const existingIds = new Set((membersArr || []).map(m => m.user_id));
        return users.filter(u => u.is_active && !existingIds.has(u.id));
    }

    it('extracts users from {data:[...], total:N} response', () => {
        const usersResp = { data: [
            { id: 'u1', username: 'alice', is_active: true },
            { id: 'u2', username: 'bob', is_active: true },
        ], total: 2};
        const membersArr = [];
        const available = getAvailableUsers(usersResp, membersArr);
        assert.equal(available.length, 2);
    });

    it('excludes existing team members', () => {
        const usersResp = { data: [
            { id: 'u1', username: 'alice', is_active: true },
            { id: 'u2', username: 'bob', is_active: true },
        ], total: 2};
        const membersArr = [{ user_id: 'u1', role: 'admin' }];
        const available = getAvailableUsers(usersResp, membersArr);
        assert.equal(available.length, 1);
        assert.equal(available[0].id, 'u2');
    });

    it('excludes inactive users', () => {
        const usersResp = { data: [
            { id: 'u1', username: 'alice', is_active: true },
            { id: 'u2', username: 'disabled', is_active: false },
        ], total: 2};
        const membersArr = [];
        const available = getAvailableUsers(usersResp, membersArr);
        assert.equal(available.length, 1);
        assert.equal(available[0].id, 'u1');
    });

    it('returns empty for empty users response', () => {
        const available = getAvailableUsers({ data: [] }, []);
        assert.equal(available.length, 0);
    });

    it('handles completely missing response fields', () => {
        const available = getAvailableUsers({}, []);
        assert.equal(available.length, 0);
    });
});

// ── Kernel surface template ──────────────────
// v0.1.0: Chat surface removed. Verify admin mount exists and
// old SPA scaffold is gone.

describe('Kernel surface templates (v0.1.0)', () => {
    const templateSrc = readAllTemplates();

    it('admin-mount div exists', () => {
        assert.ok(templateSrc.includes('id="admin-mount"'),
            'MISSING: #admin-mount — Preact admin surface cannot render');
    });

    it('old appContainer div is gone', () => {
        assert.ok(!templateSrc.includes('id="appContainer"'),
            'STALE: #appContainer still in templates — old SPA scaffold not removed');
    });

    it('admin template loads SDK boot', () => {
        assert.ok(templateSrc.includes('sw/sdk/index.js'),
            'MISSING: SDK boot import in admin template');
    });
});

// ── Admin Preact surface ─────────────────────
// v0.37.6: Admin surface handles settings save via Preact.
// Verify the admin surface has policy key handling.

describe('Admin Preact surface handles settings', () => {
    const SURFACES = path.join(SRC, 'sw', 'surfaces', 'admin');
    const settingsPath = path.join(SURFACES, 'settings.js');

    // Only test if the admin settings component exists
    if (fs.existsSync(settingsPath)) {
        const settingsSrc = fs.readFileSync(settingsPath, 'utf-8');

        it('admin settings component references allow_registration', () => {
            assert.ok(settingsSrc.includes('allow_registration'),
                'MISSING: allow_registration in admin settings component');
        });
    }
});
