import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { mkdtempSync, rmSync, writeFileSync } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { resolveTlsOptions } from './tls-options.js';
import { SERVER_TLS_DEFAULTS } from '../server/config.js';
import { ensureSelfSignedCert } from './self-signed.js';

let dir: string;
beforeEach(() => { dir = mkdtempSync(join(tmpdir(), 'tlsopt-')); });
afterEach(() => { rmSync(dir, { recursive: true, force: true }); });

describe('resolveTlsOptions', () => {
  it('returns a self-signed pair when no cert_file is configured', () => {
    const opts = resolveTlsOptions({ ...SERVER_TLS_DEFAULTS, enabled: true, selfSignedDir: dir });
    expect(opts.cert).toContain('BEGIN CERTIFICATE');
    expect(opts.key).toContain('PRIVATE KEY');
    expect(opts.minVersion).toBe('TLSv1.2');
  });

  it('uses provided PEM files when cert_file and key_file are set', () => {
    const { cert, key } = ensureSelfSignedCert(dir, []);
    writeFileSync(join(dir, 'my.crt'), cert);
    writeFileSync(join(dir, 'my.key'), key);
    const opts = resolveTlsOptions({
      ...SERVER_TLS_DEFAULTS, enabled: true,
      certFile: join(dir, 'my.crt'), keyFile: join(dir, 'my.key'),
    });
    expect(opts.cert).toBe(cert);
    expect(opts.key).toBe(key);
  });

  it('fails closed (throws) when cert_file is unreadable — never self-signs', () => {
    expect(() =>
      resolveTlsOptions({
        ...SERVER_TLS_DEFAULTS, enabled: true,
        certFile: join(dir, 'missing.crt'), keyFile: join(dir, 'missing.key'),
      }),
    ).toThrow();
  });

  it('fails closed when the provided cert is malformed PEM', () => {
    writeFileSync(join(dir, 'bad.crt'), 'garbage');
    writeFileSync(join(dir, 'bad.key'), 'garbage');
    expect(() =>
      resolveTlsOptions({
        ...SERVER_TLS_DEFAULTS, enabled: true,
        certFile: join(dir, 'bad.crt'), keyFile: join(dir, 'bad.key'),
      }),
    ).toThrow();
  });

  it('fails closed when provided cert and key do not match', () => {
    const a = ensureSelfSignedCert(dir, []);
    const dir2 = mkdtempSync(join(tmpdir(), 'tlsopt2-'));
    const b = ensureSelfSignedCert(dir2, ['other']);
    writeFileSync(join(dir, 'a.crt'), a.cert);
    writeFileSync(join(dir, 'b.key'), b.key);
    expect(() =>
      resolveTlsOptions({
        ...SERVER_TLS_DEFAULTS, enabled: true,
        certFile: join(dir, 'a.crt'), keyFile: join(dir, 'b.key'),
      }),
    ).toThrow();
    rmSync(dir2, { recursive: true, force: true });
  });
});
