import type { AwilixContainer } from 'awilix';
import { getLogger } from '@stock-bot/logger';
import type { ServiceDefinitions } from '../container/types';

interface ServiceWithLifecycle {
  connect?: () => Promise<void>;
  disconnect?: () => Promise<void>;
  close?: () => Promise<void>;
  initialize?: () => Promise<void>;
  shutdown?: () => Promise<void>;
}

export class ServiceLifecycleManager {
  private readonly logger = getLogger('service-lifecycle');
  private readonly services = [
    { name: 'cache', key: 'cache' as const },
    { name: 'mongoClient', key: 'mongoClient' as const },
    { name: 'postgresClient', key: 'postgresClient' as const },
    { name: 'questdbClient', key: 'questdbClient' as const },
    { name: 'proxyManager', key: 'proxyManager' as const },
    { name: 'queueManager', key: 'queueManager' as const },
  ];

  async initializeServices(
    container: AwilixContainer<ServiceDefinitions>,
    timeout = 30000
  ): Promise<void> {
    const initPromises: Promise<void>[] = [];

    for (const { name, key } of this.services) {
      const service = container.cradle[key] as ServiceWithLifecycle | null;

      if (service) {
        const initPromise = this.initializeService(name, service);
        initPromises.push(
          Promise.race([
            initPromise,
            this.createTimeoutPromise(
              timeout,
              `${name} initialization timed out after ${timeout}ms`
            ),
          ])
        );
      }
    }

    await Promise.all(initPromises);
    this.logger.info('All services initialized successfully');
  }

  async shutdownServices(container: AwilixContainer<ServiceDefinitions>): Promise<void> {
    const shutdownPromises: Promise<void>[] = [];

    // Shutdown in reverse order
    for (const { name, key } of [...this.services].reverse()) {
      const service = container.cradle[key] as ServiceWithLifecycle | null;

      if (service) {
        shutdownPromises.push(this.shutdownService(name, service));
      }
    }

    await Promise.allSettled(shutdownPromises);
    this.logger.info('All services shut down');
  }

  private async initializeService(name: string, service: ServiceWithLifecycle): Promise<void> {
    try {
      if (typeof service.connect === 'function') {
        await service.connect();
        this.logger.info(`${name} connected`);
      } else if (typeof service.initialize === 'function') {
        await service.initialize();
        this.logger.info(`${name} initialized`);
      }
    } catch (error) {
      this.logger.error(`Failed to initialize ${name}:`, error);
      throw error;
    }
  }

  private async shutdownService(name: string, service: ServiceWithLifecycle): Promise<void> {
    try {
      if (typeof service.disconnect === 'function') {
        await service.disconnect();
      } else if (typeof service.close === 'function') {
        await service.close();
      } else if (typeof service.shutdown === 'function') {
        await service.shutdown();
      }
      this.logger.info(`${name} shut down`);
    } catch (error) {
      this.logger.error(`Error shutting down ${name}:`, error);
    }
  }

  private createTimeoutPromise(timeout: number, message: string): Promise<never> {
    return new Promise((_, reject) => {
      setTimeout(() => reject(new Error(message)), timeout);
    });
  }
}
