import { jsx as _jsx } from "react/jsx-runtime";
// @vitest-environment happy-dom
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
// The Security tab reads `/security` (computed posture + summaries + editable
// policy), saves via PUT `/security`, and revokes sessions via POST.
let securityData;
const cmsApi = vi.fn(async (endpoint, options) => {
    const method = options?.method ?? 'GET';
    if (endpoint === '/security' && method === 'GET')
        return { data: securityData, status: 200 };
    if (endpoint === '/security' && method === 'PUT') {
        const body = JSON.parse(String(options?.body ?? '{}'));
        securityData = {
            ...securityData,
            settings: {
                mfa: { required: body.mfa.required, gracePeriodDays: body.mfa.gracePeriodDays },
                session: { maxConcurrentSessions: body.session.maxConcurrentSessions },
            },
        };
        return { data: securityData, status: 200 };
    }
    if (endpoint === '/security/sessions/revoke-all' && method === 'POST')
        return { data: { revoked: 2 }, status: 200 };
    return { data: {}, status: 200 };
});
vi.mock('../../lib/api.js', () => ({ cmsApi: (e, o) => cmsApi(e, o) }));
const { SecurityTab } = await import('../../views/settings/SecurityTab.js');
function baseData(overrides = {}) {
    return {
        settings: {
            mfa: { required: false, gracePeriodDays: 7 },
            session: { maxConcurrentSessions: 5 },
        },
        status: {
            status: 'needs_attention',
            score: 88,
            label: 'Needs attention',
            description: 'Some recommended controls are missing.',
            checks: [
                { key: 'mfa', label: 'MFA coverage', status: 'warning', value: '1 of 2 admins' },
                { key: 'csrf', label: 'CSRF protection', status: 'pass', value: 'Enabled' },
            ],
            warnings: [
                {
                    id: 'mfa-not-required',
                    severity: 'warning',
                    category: 'auth',
                    title: 'MFA is not required in production',
                    description: 'Requiring MFA reduces account-takeover risk.',
                },
            ],
            lastCheckedAt: '2026-06-01T00:00:00.000Z',
        },
        users: {
            totalUsers: 3,
            totalAdmins: 2,
            withMfa: 1,
            withoutMfa: 2,
            adminsWithoutMfa: 1,
            inactive: 0,
        },
        apiKeys: { active: 1, withoutExpiration: 0, broadScope: 0, staleUnused90d: 0 },
        secrets: {
            cmsSecret: 'pass',
            encryptionKey: 'pass',
            rateLimitBackend: 'distributed',
            apiKeysHashed: true,
            webhookSecretsEncrypted: true,
        },
        ipAllowlist: {
            enabled: false,
            source: 'none',
            ranges: [],
            currentIp: '1.2.3.4',
            currentIpAllowed: null,
        },
        failedLogins24h: 0,
        activeSessions: 2,
        csrfEnabled: true,
        uploadValidation: true,
        auditEnabled: true,
        sessionMaxAgeHours: 168,
        viewerHasMfa: true,
        environment: 'production',
        sources: {
            ipAllowlist: { source: 'config', editable: false },
            csrf: { source: 'computed', editable: false },
            rateLimiting: { source: 'environment', editable: false },
            uploadValidation: { source: 'computed', editable: false },
            cmsSecret: { source: 'environment', editable: false },
            encryptionKey: { source: 'environment', editable: false },
            audit: { source: 'computed', editable: false },
        },
        ...overrides,
    };
}
beforeEach(() => {
    cmsApi.mockClear();
    securityData = baseData();
});
describe('SecurityTab', () => {
    it('renders the status card and all security sections with a disabled save bar', async () => {
        render(_jsx(SecurityTab, { role: "ADMIN" }));
        await screen.findByText('Security Status');
        expect(screen.getByText('Authentication & MFA')).toBeTruthy();
        expect(screen.getByText('Session Policy')).toBeTruthy();
        expect(screen.getByText('Access & Request Protection')).toBeTruthy();
        expect(screen.getByText('Secrets, Encryption & Audit')).toBeTruthy();
        // Status badge + warning surfaced.
        expect(screen.getByText('Needs attention')).toBeTruthy();
        expect(screen.getByText('MFA is not required in production')).toBeTruthy();
        expect(screen.getByRole('button', { name: 'Save Changes' }).disabled).toBe(true);
    });
    it('enables Save when concurrent-session cap changes and persists via PUT /security', async () => {
        render(_jsx(SecurityTab, { role: "ADMIN" }));
        await screen.findByText('Security Status');
        const select = screen.getByLabelText(/Maximum concurrent sessions/);
        fireEvent.change(select, { target: { value: '3' } });
        const save = screen.getByRole('button', { name: 'Save Changes' });
        expect(save.disabled).toBe(false);
        fireEvent.click(save);
        await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/security', expect.objectContaining({
            method: 'PUT',
            body: expect.stringContaining('"maxConcurrentSessions":3'),
        })));
    });
    it('blocks enabling Require MFA (lockout-safe) when the acting admin has no MFA', async () => {
        securityData = baseData({ viewerHasMfa: false });
        render(_jsx(SecurityTab, { role: "ADMIN" }));
        await screen.findByText('Security Status');
        const toggle = screen.getByRole('switch', {
            name: 'Require MFA for admin users',
        });
        // Toggle is disabled until the admin sets up their own MFA.
        expect(toggle.disabled).toBe(true);
        expect(screen.getByText(/Set up MFA on your own account/i)).toBeTruthy();
    });
    it('confirms before requiring MFA and then persists it (admin has MFA)', async () => {
        render(_jsx(SecurityTab, { role: "ADMIN" }));
        await screen.findByText('Security Status');
        fireEvent.click(screen.getByRole('switch', { name: 'Require MFA for admin users' }));
        // Confirmation dialog appears; nothing saved yet.
        const confirm = await screen.findByRole('button', { name: 'Require MFA' });
        fireEvent.click(confirm);
        const save = screen.getByRole('button', { name: 'Save Changes' });
        expect(save.disabled).toBe(false);
        fireEvent.click(save);
        await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/security', expect.objectContaining({
            method: 'PUT',
            body: expect.stringContaining('"required":true'),
        })));
    });
    it('revokes other sessions through a confirmation flow', async () => {
        render(_jsx(SecurityTab, { role: "ADMIN" }));
        await screen.findByText('Security Status');
        fireEvent.click(screen.getByRole('button', { name: 'Revoke other sessions' }));
        const confirm = await screen.findByRole('button', { name: 'Revoke sessions' });
        fireEvent.click(confirm);
        await waitFor(() => expect(cmsApi).toHaveBeenCalledWith('/security/sessions/revoke-all', expect.objectContaining({ method: 'POST' })));
        await screen.findByText('Other sessions revoked.');
    });
    it('is read-only for non-admin roles', async () => {
        render(_jsx(SecurityTab, { role: "EDITOR" }));
        await screen.findByText('Security Status');
        expect(screen.getByText(/read-only access/i)).toBeTruthy();
        const toggle = screen.getByRole('switch', {
            name: 'Require MFA for admin users',
        });
        expect(toggle.disabled).toBe(true);
        const select = screen.getByLabelText(/Maximum concurrent sessions/);
        expect(select.disabled).toBe(true);
    });
});
//# sourceMappingURL=security-settings.render.test.js.map