import {
  Injectable,
  Logger,
  OnModuleDestroy,
  OnModuleInit,
} from '@nestjs/common';
import Redis from 'ioredis';

import { getConfig } from '@hexahost/config';

import { NODE_COMMANDS_CHANNEL } from '../servers/servers.service';

import { NodesService } from './nodes.service';

interface NodeCommandMessage {
  nodeId: string;
  envelope: unknown;
}

@Injectable()
export class NodeCommandSubscriber implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger(NodeCommandSubscriber.name);
  private subscriber?: Redis;

  constructor(private readonly nodesService: NodesService) {}

  async onModuleInit(): Promise<void> {
    const config = getConfig();
    this.subscriber = new Redis(config.REDIS_URL, {
      maxRetriesPerRequest: null,
    });

    await this.subscriber.subscribe(NODE_COMMANDS_CHANNEL);

    this.subscriber.on('message', (channel, message) => {
      if (channel !== NODE_COMMANDS_CHANNEL) {
        return;
      }

      try {
        const parsed = JSON.parse(message) as NodeCommandMessage;

        if (!parsed.nodeId || parsed.envelope === undefined) {
          this.logger.warn('Ignoring malformed node command message');
          return;
        }

        this.nodesService.forwardCommand(parsed.nodeId, parsed.envelope);
      } catch (error) {
        const detail = error instanceof Error ? error.message : String(error);
        this.logger.error(`Failed to process node command: ${detail}`);
      }
    });
  }

  async onModuleDestroy(): Promise<void> {
    if (!this.subscriber) {
      return;
    }

    await this.subscriber.unsubscribe(NODE_COMMANDS_CHANNEL);
    await this.subscriber.quit();
  }
}
