import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, readFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { SecurityProfileStore, sanitizeSecurityProfile } from '../lib/security/security-profile-store.mjs';
import { createTerminalToolRegistry } from '../lib/agent/terminal-tools.mjs';

const SECRET = 'test-only-security-profile-key-at-least-32-chars';

function profile() {
  return {
    language: 'de',
    preferredName: 'Test Operator',
    location: { country: 'Deutschland', region: 'NRW', city: 'Koeln' },
    timezone: 'Europe/Berlin',
    household: { adults: 2, children: 1, pets: 1 },
    mobility: ['car', 'rail'],
    riskPriorities: ['weather', 'cyber'],
    criticalDependencies: ['electricity', 'internet'],
    alertPreference: 'important',
    quietHours: '22:00-07:00',
    consentedAt: new Date().toISOString(),
  };
}

test('security profile is encrypted at rest and reloads with the correct key', () => {
  const path = join(mkdtempSync(join(tmpdir(), 'security-profile-')), 'profile.enc');
  const store = new SecurityProfileStore(path, SECRET).init();
  store.save(profile());

  const raw = readFileSync(path, 'utf8');
  assert.equal(raw.includes('Test Operator'), false);
  assert.equal(raw.includes('Koeln'), false);
  assert.equal(JSON.parse(raw).algorithm, 'aes-256-gcm');

  const restored = new SecurityProfileStore(path, SECRET).init();
  assert.equal(restored.getProfile().preferredName, 'Test Operator');
  assert.equal(restored.getProfile().location.city, 'Koeln');
});

test('wrong key fails closed and cannot overwrite an existing profile', () => {
  const path = join(mkdtempSync(join(tmpdir(), 'security-profile-')), 'profile.enc');
  new SecurityProfileStore(path, SECRET).init().save(profile());
  const wrong = new SecurityProfileStore(path, 'another-test-key-that-is-at-least-32-characters').init();
  assert.equal(wrong.status().configured, true);
  assert.equal(wrong.status().available, false);
  assert.equal(wrong.getProfile(), null);
  assert.throws(() => wrong.save(profile()));
});

test('profile sanitizer only retains allowlisted risk and dependency categories', () => {
  const value = sanitizeSecurityProfile({
    ...profile(),
    riskPriorities: ['weather', 'passwords'],
    criticalDependencies: ['internet', 'bank-login'],
    household: { adults: 999, children: -4, pets: 2 },
  });
  assert.deepEqual(value.riskPriorities, ['weather']);
  assert.deepEqual(value.criticalDependencies, ['internet']);
  assert.deepEqual(value.household, { adults: 20, children: 0, pets: 2 });
});

test('agent can read only the approved profile through the allowlisted tool', async () => {
  const path = join(mkdtempSync(join(tmpdir(), 'security-profile-')), 'profile.enc');
  const store = new SecurityProfileStore(path, SECRET).init();
  store.save(profile());
  const registry = createTerminalToolRegistry({ securityProfileStore: store });
  const result = await registry.execute('get_security_profile');
  assert.equal(result.available, true);
  assert.equal(result.profile.location.country, 'Deutschland');
  assert.equal(Object.hasOwn(result.profile, 'completedAt'), false);
});

test('deleting a security profile removes it from the store', () => {
  const path = join(mkdtempSync(join(tmpdir(), 'security-profile-')), 'profile.enc');
  const store = new SecurityProfileStore(path, SECRET).init();
  store.save(profile());
  store.delete();
  assert.equal(store.exists, false);
  assert.equal(store.getProfile(), null);
});
