import path from 'node:path';
import { ConfigLoader } from '@zyphon/config-loader';
import { DailyLogWriter, DailyLogReader } from '@zyphon/logger';
import { CredentialVault } from './core/credential-vault.js';
import { QuotaManager } from './core/quota-manager.js';
import { ApplicationRegistry } from './core/application-registry.js';
import { CircuitBreakerManager } from './core/circuit-breaker.js';
import { RoutingEngine } from './core/routing-engine.js';
import { ProviderRegistry } from './core/provider-registry.js';
import { IdempotencyManager } from './core/idempotency-manager.js';
import { EventBus } from './realtime/event-bus.js';
import { MetricsCollector } from './core/metrics.js';
import { DispatchService } from './messaging/dispatch-service.js';
import { AdminAuthManager } from './auth/admin-auth.js';
import { LogJanitor } from './autonomous/log-janitor.js';
import { ConfigWatcher } from './autonomous/config-watcher.js';
import { HealthMonitor } from './autonomous/health-monitor.js';
import { createGatewayServers } from './server.js';
import { SmtpProviderAdapter } from '@zyphon/provider-email-smtp';
import { SendGridProviderAdapter } from '@zyphon/provider-email-sendgrid';
import { SesProviderAdapter } from '@zyphon/provider-email-ses';
import { ZohoEmailProviderAdapter } from '@zyphon/provider-email-zoho';
import { TwilioSmsProviderAdapter } from '@zyphon/provider-sms-twilio';
import { MetaWhatsAppProviderAdapter } from '@zyphon/provider-whatsapp-meta';
import { TwilioWhatsAppProviderAdapter } from '@zyphon/provider-whatsapp-twilio';
import { InboundSmtpRelay } from './smtp-relay/relay-server.js';
import type { ProviderAdapter } from '@zyphon/provider-contracts';
import { createAdapter } from './core/adapter-factory.js';

async function bootstrap() {
  const configDir = process.env.ZYPHON_CONFIG_DIR || './config';
  const dataDir = process.env.ZYPHON_DATA_DIR || './data';
  const stateDir = path.join(dataDir, 'state');
  const logsDir = path.join(dataDir, 'logs');

  const publicPort = parseInt(process.env.PORT || '8080', 10);
  const adminPort = parseInt(process.env.ADMIN_PORT || '8081', 10);
  const host = process.env.HOST || '0.0.0.0';

  console.log(`[ZYPHON] Starting Zyphon Unified Messaging Gateway...`);
  console.log(`[ZYPHON] Config: ${path.resolve(configDir)} | Data: ${path.resolve(dataDir)}`);

  // 1. Config Loader
  const configLoader = new ConfigLoader(configDir, stateDir);
  const clusterConfig = configLoader.loadClusterConfig();

  // 2. Logging
  const logWriter = new DailyLogWriter({ logsDir, retentionDays: 7 });
  const logReader = new DailyLogReader(logsDir);

  // 3. Vault & Quota
  const vaultFilePath = path.join(stateDir, 'vault.enc.json');
  const vault = new CredentialVault(vaultFilePath);
  const quotaManager = new QuotaManager(stateDir);

  // 4. Application Registry
  const appRegistry = new ApplicationRegistry(clusterConfig.applications, quotaManager, stateDir);

  // 5. Circuit Breaker & Routing Engine
  const circuitBreaker = new CircuitBreakerManager({
    failureThreshold: clusterConfig.routing.circuit_breaker?.failure_threshold ?? 3,
    recoveryTimeSeconds: clusterConfig.routing.circuit_breaker?.recovery_time_seconds ?? 20,
  });
  const routingEngine = new RoutingEngine(clusterConfig.routing, circuitBreaker);

  // 6. Provider Registry & Mock Providers
  const providerRegistry = new ProviderRegistry(vault);

  // Register only providers from config/providers.yaml (empty = none; add via dashboard).
  for (const provDef of clusterConfig.providers) {
    const adapter = createAdapter(provDef);
    providerRegistry.registerAdapter(adapter, provDef as any);
  }

  // 7. Event Bus, Metrics, Idempotency & Dispatch Service
  const eventBus = new EventBus(1000);
  const metrics = new MetricsCollector();
  const idempotencyManager = new IdempotencyManager(5, 5000);

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

  // 8. Admin Auth
  const adminAuth = new AdminAuthManager();

  // 9. Autonomous Jobs
  const logJanitor = new LogJanitor(logWriter, eventBus, 7);
  logJanitor.start();

  const configWatcher = new ConfigWatcher({
    configDir,
    configLoader,
    appRegistry,
    routingEngine,
    eventBus,
  });
  configWatcher.start();

  const healthMonitor = new HealthMonitor({
    providerRegistry,
    eventBus,
    circuitBreaker,
    intervalMs: 15000,
  });
  healthMonitor.start();

  // 10. Fastify Servers
  const { publicApp, adminApp } = createGatewayServers({
    dispatchService,
    appRegistry,
    routingEngine,
    vault,
    circuitBreaker,
    providerRegistry,
    eventBus,
    adminAuth,
    metrics,
    logWriter,
    logReader,
    configLoader,
    stateDir,
  });

  // Optional Inbound SMTP Relay
  let smtpRelay: InboundSmtpRelay | null = null;
  if (clusterConfig.server.smtp_relay?.enabled) {
    smtpRelay = new InboundSmtpRelay(dispatchService, appRegistry, {
      port: clusterConfig.server.smtp_relay.port || 2525,
      host: clusterConfig.server.smtp_relay.host || host,
    });
    await smtpRelay.start();
    console.log(`[ZYPHON] Inbound SMTP Relay listening on port ${clusterConfig.server.smtp_relay.port || 2525}`);
  }

  await publicApp.listen({ port: publicPort, host });
  console.log(`[ZYPHON] Public API listening on http://${host}:${publicPort}`);

  await adminApp.listen({ port: adminPort, host });
  console.log(`[ZYPHON] Admin API listening on http://${host}:${adminPort}`);

  // Graceful Shutdown
  const shutdown = async (signal: string) => {
    console.log(`[ZYPHON] Received ${signal}. Shutting down gracefully...`);
    healthMonitor.stop();
    logJanitor.stop();
    configWatcher.stop();
    await Promise.allSettled([publicApp.close(), adminApp.close()]);
    await dispatchService.drainPendingDispatches(30_000);
    if (dispatchService.getPendingAsyncCount() > 0) {
      console.warn(
        `[ZYPHON] Shutdown with ${dispatchService.getPendingAsyncCount()} async dispatch(es) still in flight`
      );
    }
    eventBus.stop();
    quotaManager.stop();
    if (smtpRelay) await smtpRelay.stop();
    console.log(`[ZYPHON] Shutdown complete.`);
    process.exit(0);
  };

  process.on('SIGINT', () => shutdown('SIGINT'));
  process.on('SIGTERM', () => shutdown('SIGTERM'));

  return { publicApp, adminApp };
}

// Start if executed directly
if (process.env.NODE_ENV !== 'test') {
  bootstrap().catch((err) => {
    console.error(`[ZYPHON] Fatal startup error:`, err);
    process.exit(1);
  });
}


export { bootstrap, createAdapter };
