import {
  Inject,
  Injectable,
  Logger,
  type OnApplicationBootstrap,
  type OnApplicationShutdown,
} from '@nestjs/common';
import type { SystemReloadPayload } from '@mosaicstack/types';
import { CommandRegistryService } from '../commands/command-registry.service.js';
import { isMosaicPlugin } from './mosaic-plugin.interface.js';

@Injectable()
export class ReloadService implements OnApplicationBootstrap, OnApplicationShutdown {
  private readonly logger = new Logger(ReloadService.name);
  private readonly plugins: Map<string, unknown> = new Map();
  private shutdownHandlerAttached = false;

  constructor(
    @Inject(CommandRegistryService) private readonly commandRegistry: CommandRegistryService,
  ) {}

  onApplicationBootstrap(): void {
    if (!this.shutdownHandlerAttached) {
      process.on('SIGHUP', () => {
        this.logger.log('SIGHUP received — triggering soft reload');
        this.reload('sighup').catch((err: unknown) => {
          this.logger.error(`SIGHUP reload failed: ${err}`);
        });
      });
      this.shutdownHandlerAttached = true;
    }
  }

  onApplicationShutdown(): void {
    process.removeAllListeners('SIGHUP');
  }

  registerPlugin(name: string, plugin: unknown): void {
    this.plugins.set(name, plugin);
    this.logger.log(`Plugin registered: ${name}`);
  }

  /**
   * Soft reload — unload plugins, reload plugins, broadcast.
   * Does NOT restart the HTTP server or drop connections.
   */
  async reload(
    trigger: 'command' | 'rest' | 'sighup' | 'file-watch',
  ): Promise<SystemReloadPayload> {
    this.logger.log(`Soft reload triggered by: ${trigger}`);
    const reloaded: string[] = [];
    const errors: string[] = [];

    // 1. Unload all registered MosaicPlugin instances
    for (const [name, plugin] of this.plugins) {
      if (isMosaicPlugin(plugin)) {
        try {
          await plugin.onUnload();
          reloaded.push(name);
        } catch (err) {
          errors.push(`${name}: unload failed — ${err}`);
        }
      }
    }

    // 2. Reload all MosaicPlugin instances
    for (const [name, plugin] of this.plugins) {
      if (isMosaicPlugin(plugin)) {
        try {
          await plugin.onLoad();
        } catch (err) {
          errors.push(`${name}: load failed — ${err}`);
        }
      }
    }

    const manifest = this.commandRegistry.getManifest();

    const errorSuffix = errors.length > 0 ? ` Errors: ${errors.join(', ')}` : '';
    const payload: SystemReloadPayload = {
      commands: manifest.commands,
      skills: manifest.skills,
      providers: [],
      message: `Reload complete (trigger=${trigger}). Plugins reloaded: [${reloaded.join(', ')}].${errorSuffix}`,
    };

    this.logger.log(
      `Reload complete. Reloaded: [${reloaded.join(', ')}]. Errors: ${errors.length}`,
    );
    return payload;
  }
}
