import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { ConfigLoader } from '@zyphon/config-loader';
import { ConfigWatcher } from '../../apps/gateway/src/autonomous/config-watcher.js';
import { ApplicationRegistry } from '../../apps/gateway/src/core/application-registry.js';
import { QuotaManager } from '../../apps/gateway/src/core/quota-manager.js';
import { RoutingEngine } from '../../apps/gateway/src/core/routing-engine.js';
import { CircuitBreakerManager } from '../../apps/gateway/src/core/circuit-breaker.js';
import { EventBus } from '../../apps/gateway/src/realtime/event-bus.js';

describe('ConfigWatcher ancillary reload', () => {
  let tmp: string;
  let stateDir: string;

  beforeEach(() => {
    tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'zyphon-cw-'));
    stateDir = path.join(tmp, 'state');
    fs.mkdirSync(stateDir, { recursive: true });
    fs.writeFileSync(
      path.join(tmp, 'applications.yaml'),
      [
        'applications:',
        '  - id: a1',
        '    name: App',
        '    enabled: true',
        '    channels: [email]',
        '    quota: { per_min: 10, per_day: 100 }',
        '',
      ].join('\n'),
    );
    fs.writeFileSync(
      path.join(tmp, 'providers.yaml'),
      [
        'providers:',
        '  - id: smtp-primary',
        '    channel: email',
        '    adapter: smtp',
        '    enabled: true',
        '  - id: twilio-sms',
        '    channel: sms',
        '    adapter: twilio',
        '    enabled: true',
        '  - id: meta-whatsapp',
        '    channel: whatsapp',
        '    adapter: meta-cloud',
        '    enabled: true',
        '',
      ].join('\n'),
    );
    fs.writeFileSync(
      path.join(tmp, 'routing.yaml'),
      [
        'routing:',
        '  default:',
        '    email: [smtp-primary]',
        '    sms: [twilio-sms]',
        '    whatsapp: [meta-whatsapp]',
        '  circuit_breaker:',
        '    failure_threshold: 3',
        '    recovery_time_seconds: 20',
        '',
      ].join('\n'),
    );
    fs.writeFileSync(
      path.join(tmp, 'zyphon.yaml'),
      'server:\n  public_port: 8080\n  admin_port: 8081\n',
    );
    fs.writeFileSync(
      path.join(tmp, 'templates.yaml'),
      [
        'templates:',
        '  - id: tpl-a',
        '    name: A',
        '    channel: sms',
        '    body: "Hi {{name}}"',
        '    variables: [name]',
        '',
      ].join('\n'),
    );
    fs.writeFileSync(
      path.join(tmp, 'dlt.yaml'),
      'dlt:\n  pe_id: "1100123456789012345"\n',
    );
  });

  afterEach(() => {
    fs.rmSync(tmp, { recursive: true, force: true });
  });

  function build() {
    const configLoader = new ConfigLoader(tmp, stateDir);
    const cluster = configLoader.loadClusterConfig();
    const quota = new QuotaManager(stateDir);
    const appRegistry = new ApplicationRegistry(cluster.applications, quota, stateDir);
    const cb = new CircuitBreakerManager(cluster.routing.circuit_breaker);
    const routingEngine = new RoutingEngine(cluster.routing, cb);
    const eventBus = new EventBus(50);
    const watcher = new ConfigWatcher({
      configDir: tmp,
      configLoader,
      appRegistry,
      routingEngine,
      eventBus,
    });
    return { watcher, eventBus };
  }

  it('validates templates.yaml and publishes config_reloaded', () => {
    const { watcher, eventBus } = build();
    const events: string[] = [];
    eventBus.on('event', (ev: { event: string }) => events.push(ev.event));

    const ok = watcher.handleConfigChange(['templates.yaml']);
    expect(ok).toBe(true);
    expect(events).toContain('config_reloaded');
  });

  it('rejects invalid templates without crashing', () => {
    fs.writeFileSync(path.join(tmp, 'templates.yaml'), 'templates:\n  - id: broken\n');
    const { watcher, eventBus } = build();
    const events: string[] = [];
    eventBus.on('event', (ev: { event: string }) => events.push(ev.event));

    const ok = watcher.handleConfigChange(['templates.yaml']);
    expect(ok).toBe(false);
    expect(events).toContain('config_reload_failed');
  });
});
