import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import * as fs from 'node:fs/promises';
import * as path from 'node:path';
import * as os from 'node:os';
import { createGatewayServers } from '../../apps/gateway/src/server.js';
import { ConfigLoader } from '@zyphon/config-loader';
import { DailyLogWriter, DailyLogReader } from '@zyphon/logger';
import { CredentialVault } from '../../apps/gateway/src/core/credential-vault.js';
import { QuotaManager } from '../../apps/gateway/src/core/quota-manager.js';
import { ApplicationRegistry } from '../../apps/gateway/src/core/application-registry.js';
import { CircuitBreakerManager } from '../../apps/gateway/src/core/circuit-breaker.js';
import { RoutingEngine } from '../../apps/gateway/src/core/routing-engine.js';
import { ProviderRegistry } from '../../apps/gateway/src/core/provider-registry.js';
import { IdempotencyManager } from '../../apps/gateway/src/core/idempotency-manager.js';
import { EventBus } from '../../apps/gateway/src/realtime/event-bus.js';
import { MetricsCollector } from '../../apps/gateway/src/core/metrics.js';
import { DispatchService } from '../../apps/gateway/src/messaging/dispatch-service.js';
import { AdminAuthManager } from '../../apps/gateway/src/auth/admin-auth.js';
import { MockProvider } from '@zyphon/provider-mock';
import { resolveMasterKey } from '@zyphon/crypto';

describe('Gateway Health Endpoints', () => {
  let tmpDir: string;
  let servers: ReturnType<typeof createGatewayServers>;
  let quotaManager: QuotaManager;
  let eventBus: EventBus;

  beforeEach(async () => {
    tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'zyphon-gw-test-'));
    const configDir = path.join(tmpDir, 'config');
    const stateDir = path.join(tmpDir, 'data', 'state');
    const logsDir = path.join(tmpDir, 'data', 'logs');

    await fs.mkdir(configDir, { recursive: true });
    await fs.mkdir(stateDir, { recursive: true });
    await fs.mkdir(logsDir, { recursive: true });

    const masterKey = resolveMasterKey('0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef');
    const vault = new CredentialVault(path.join(stateDir, 'vault.enc.json'), masterKey);
    quotaManager = new QuotaManager(stateDir);
    const appRegistry = new ApplicationRegistry([], quotaManager, stateDir);
    const circuitBreaker = new CircuitBreakerManager();
    const routingEngine = new RoutingEngine({
      default: { email: ['mock-email'], sms: ['mock-sms'], whatsapp: ['mock-whatsapp'] },
      retry: { max_attempts: 2, backoff_ms: 10 },
      timeout_ms: { email: 1000, sms: 1000, whatsapp: 1000 },
    }, circuitBreaker);

    const providerRegistry = new ProviderRegistry(vault);
    providerRegistry.registerAdapter(new MockProvider({ id: 'mock-email', channel: 'email' }));

    const logWriter = new DailyLogWriter({ logsDir });
    const logReader = new DailyLogReader(logsDir);
    eventBus = new EventBus(100);
    const idempotencyManager = new IdempotencyManager(5, 100);
    const metrics = new MetricsCollector();

    const dispatchService = new DispatchService({
      appRegistry,
      routingEngine,
      vault,
      circuitBreaker,
      idempotencyManager,
      providerRegistry,
      logWriter,
      eventBus,
    });

    const adminAuth = new AdminAuthManager('test-admin-secret');
    const configLoader = new ConfigLoader(configDir, stateDir);

    servers = createGatewayServers({
      dispatchService,
      appRegistry,
      routingEngine,
      vault,
      circuitBreaker,
      providerRegistry,
      eventBus,
      adminAuth,
      metrics,
      logWriter,
      logReader,
      configLoader,
    });
  });

  afterEach(async () => {
    quotaManager.stop();
    eventBus.stop();
    await servers.publicApp.close();
    await servers.adminApp.close();
    await fs.rm(tmpDir, { recursive: true, force: true });
  });

  it('GET /api/v1/health returns ok', async () => {
    const res = await servers.publicApp.inject({
      method: 'GET',
      url: '/api/v1/health',
    });

    expect(res.statusCode).toBe(200);
    const body = JSON.parse(res.body);
    expect(body.status).toBe('ok');
    expect(typeof body.uptime).toBe('number');
  });

  it('GET /admin/health returns provider health breakdown', async () => {
    const res = await servers.adminApp.inject({
      method: 'GET',
      url: '/admin/health',
    });

    expect(res.statusCode).toBe(200);
    const body = JSON.parse(res.body);
    expect(body.status).toBe('ok');
    expect(body.providers).toBeDefined();
    expect(body.providers['mock-email']).toBeDefined();
    expect(body.providers['mock-email'].status).toBe('healthy');
  });
});

