import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import Fastify from 'fastify';
import cookie from '@fastify/cookie';
import Database from 'better-sqlite3';
import fs from 'node:fs';
import path from 'node:path';
import os from 'node:os';
import { settingsRoutes, parseEnvFile, maskValue } from '../settings-routes.js';
import { registerAuthMiddleware } from '../../auth/auth-middleware.js';
import { authRoutes } from '../../auth/auth-routes.js';
import { hashPassword } from '../../auth/password.js';
import { runMigrations } from '../../db/migrations.js';
const SECRET = 'test-secret-that-is-at-least-32-chars-long!!';
async function buildApp(db) {
    const app = Fastify();
    await app.register(cookie);
    registerAuthMiddleware(app, SECRET);
    await app.register(authRoutes, { db, jwtSecret: SECRET });
    await app.register(settingsRoutes);
    await app.ready();
    return app;
}
async function getAuthCookie(app) {
    const res = await app.inject({
        method: 'POST',
        url: '/api/auth/login',
        payload: { username: 'admin', password: 'admin123' },
    });
    const cookies = res.cookies;
    const accessToken = cookies.find(c => c.name === 'access_token');
    return `access_token=${accessToken.value}`;
}
describe('settings routes', () => {
    let db;
    let app;
    let authCookie;
    let tmpEnvPath;
    let origDotenvPath;
    beforeEach(async () => {
        db = new Database(':memory:');
        runMigrations(db);
        const hash = await hashPassword('admin123');
        db.prepare("INSERT INTO users (id, username, password_hash, role, created_at) VALUES (?, ?, ?, ?, ?)").run('admin-id', 'admin', hash, 'admin', new Date().toISOString());
        // Create temp .env file
        tmpEnvPath = path.join(os.tmpdir(), `.env-test-${Date.now()}`);
        fs.writeFileSync(tmpEnvPath, 'AWS_REGION=us-east-1\nSES_FROM_EMAIL=test@example.com\nJWT_SECRET=should-not-be-exposed\n');
        origDotenvPath = process.env.DOTENV_PATH;
        process.env.DOTENV_PATH = tmpEnvPath;
        app = await buildApp(db);
        authCookie = await getAuthCookie(app);
    });
    afterEach(async () => {
        await app?.close();
        db?.close();
        if (origDotenvPath !== undefined) {
            process.env.DOTENV_PATH = origDotenvPath;
        }
        else {
            delete process.env.DOTENV_PATH;
        }
        try {
            fs.unlinkSync(tmpEnvPath);
        }
        catch { /* ignore */ }
    });
    it('GET /api/settings/env — returns allowed keys only', async () => {
        const res = await app.inject({
            method: 'GET',
            url: '/api/settings/env',
            headers: { cookie: authCookie },
        });
        expect(res.statusCode).toBe(200);
        const body = JSON.parse(res.payload);
        expect(body.settings.AWS_REGION).toBe('us-east-1');
        expect(body.settings.SES_FROM_EMAIL).toBe('test@example.com');
        // JWT_SECRET should NOT be in the response (not in ALLOWED_KEYS)
        expect(body.settings.JWT_SECRET).toBeUndefined();
    });
    it('GET /api/settings/env — masks secret values', async () => {
        fs.writeFileSync(tmpEnvPath, 'AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE\nAWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\n');
        const res = await app.inject({
            method: 'GET',
            url: '/api/settings/env',
            headers: { cookie: authCookie },
        });
        expect(res.statusCode).toBe(200);
        const body = JSON.parse(res.payload);
        expect(body.settings.AWS_ACCESS_KEY_ID).toBe('****MPLE');
        expect(body.settings.AWS_SECRET_ACCESS_KEY).toBe('****EKEY');
    });
    it('PATCH /api/settings/env — updates values', async () => {
        const res = await app.inject({
            method: 'PATCH',
            url: '/api/settings/env',
            headers: { cookie: authCookie },
            payload: { SES_FROM_EMAIL: 'new@example.com', AWS_REGION: 'eu-west-1' },
        });
        expect(res.statusCode).toBe(200);
        const body = JSON.parse(res.payload);
        expect(body.settings.SES_FROM_EMAIL).toBe('new@example.com');
        expect(body.settings.AWS_REGION).toBe('eu-west-1');
        // Verify file was written
        const content = fs.readFileSync(tmpEnvPath, 'utf-8');
        expect(content).toContain('SES_FROM_EMAIL=new@example.com');
        expect(content).toContain('AWS_REGION=eu-west-1');
        // Verify process.env was updated
        expect(process.env.SES_FROM_EMAIL).toBe('new@example.com');
    });
    it('PATCH /api/settings/env — rejects invalid keys', async () => {
        const res = await app.inject({
            method: 'PATCH',
            url: '/api/settings/env',
            headers: { cookie: authCookie },
            payload: { JWT_SECRET: 'hacked', SOME_RANDOM: 'value' },
        });
        expect(res.statusCode).toBe(400);
        expect(JSON.parse(res.payload).error).toContain('Invalid keys');
    });
    it('PATCH /api/settings/env — empty string removes key', async () => {
        await app.inject({
            method: 'PATCH',
            url: '/api/settings/env',
            headers: { cookie: authCookie },
            payload: { SES_FROM_EMAIL: '' },
        });
        const content = fs.readFileSync(tmpEnvPath, 'utf-8');
        expect(content).not.toContain('SES_FROM_EMAIL');
    });
    it('rejects non-admin users', async () => {
        // Create operator user
        const hash = await hashPassword('op123');
        db.prepare("INSERT INTO users (id, username, password_hash, role, created_at) VALUES (?, ?, ?, ?, ?)").run('op-id', 'operator', hash, 'operator', new Date().toISOString());
        const loginRes = await app.inject({
            method: 'POST',
            url: '/api/auth/login',
            payload: { username: 'operator', password: 'op123' },
        });
        const cookies = loginRes.cookies;
        const opCookie = `access_token=${cookies.find(c => c.name === 'access_token').value}`;
        const res = await app.inject({
            method: 'GET',
            url: '/api/settings/env',
            headers: { cookie: opCookie },
        });
        expect(res.statusCode).toBe(403);
    });
    it('rejects unauthenticated requests', async () => {
        const res = await app.inject({
            method: 'GET',
            url: '/api/settings/env',
        });
        expect(res.statusCode).toBe(401);
    });
});
describe('parseEnvFile', () => {
    it('parses key=value pairs, skips comments and blanks', () => {
        const tmpFile = path.join(os.tmpdir(), `.env-parse-${Date.now()}`);
        fs.writeFileSync(tmpFile, '# Comment\nKEY1=value1\n\nKEY2=value2\n');
        const result = parseEnvFile(tmpFile);
        expect(result.get('KEY1')).toBe('value1');
        expect(result.get('KEY2')).toBe('value2');
        expect(result.size).toBe(2);
        fs.unlinkSync(tmpFile);
    });
});
describe('maskValue', () => {
    it('masks secret keys', () => {
        expect(maskValue('AWS_ACCESS_KEY_ID', 'AKIAIOSFODNN7EXAMPLE')).toBe('****MPLE');
    });
    it('does not mask non-secret keys', () => {
        expect(maskValue('AWS_REGION', 'us-east-1')).toBe('us-east-1');
    });
    it('returns **** for short secrets', () => {
        expect(maskValue('AWS_SECRET_ACCESS_KEY', 'abc')).toBe('****');
    });
});
//# sourceMappingURL=settings-routes.test.js.map