import { Injectable, Logger, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import amqp from 'amqplib';
import { BOT_INBOUND_QUEUE, BotInboundQueueMessage } from './bot-inbound-publisher.service';
import { BotDeliveryService } from './bot-delivery.service';

@Injectable()
export class BotMessageConsumerService implements OnModuleInit, OnModuleDestroy {
  private readonly logger = new Logger(BotMessageConsumerService.name);
  private connection: { createChannel: () => Promise<amqp.Channel>; close: () => Promise<void> } | null = null;
  private channel: amqp.Channel | null = null;
  private consumerTag: string | null = null;

  constructor(
    private readonly config: ConfigService,
    private readonly delivery: BotDeliveryService
  ) {}

  async onModuleInit() {
    await this.connect();
  }

  async onModuleDestroy() {
    try {
      if (this.channel && this.consumerTag) {
        await this.channel.cancel(this.consumerTag);
      }
      await this.channel?.close();
    } catch {
      // ignore
    }
    try {
      await this.connection?.close();
    } catch {
      // ignore
    }
  }

  private async connect() {
    const url = this.config.get<string>('RABBITMQ_URL', 'amqp://lendry:lendry_password@localhost:5672/');
    try {
      this.connection = (await amqp.connect(url)) as {
        createChannel: () => Promise<amqp.Channel>;
        close: () => Promise<void>;
      };
      this.channel = await this.connection.createChannel();
      await this.channel.assertQueue(BOT_INBOUND_QUEUE, { durable: true });
      await this.channel.prefetch(10);

      const consumeResult = await this.channel.consume(BOT_INBOUND_QUEUE, (message) => {
        if (!message) return;
        void this.handleMessage(message);
      });
      this.consumerTag = consumeResult.consumerTag;
      this.logger.log(`Consumer ${BOT_INBOUND_QUEUE} запущен`);
    } catch (error) {
      this.logger.warn(
        `Не удалось запустить consumer ${BOT_INBOUND_QUEUE}: ${error instanceof Error ? error.message : error}`
      );
    }
  }

  private async handleMessage(message: amqp.Message) {
    if (!this.channel) return;

    try {
      const payload = JSON.parse(message.content.toString()) as BotInboundQueueMessage;
      await this.delivery.deliverInboundEvent(payload);
      this.channel.ack(message);
    } catch (error) {
      this.logger.error(
        `Ошибка обработки bot inbound: ${error instanceof Error ? error.message : error}`,
        error instanceof Error ? error.stack : undefined
      );
      this.channel.nack(message, false, false);
    }
  }
}
