import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { InjectQueue } from '@nestjs/bullmq';
import { Queue } from 'bullmq';
import { PrismaService } from '../../../prisma/prisma.service';
import { randomBytes, createHmac } from 'crypto';

export const TG_BOT_EVENTS = [
  'subscriber.created',
  'subscriber.blocked',
  'subscriber.phone_shared',
  'referral.invited',
  'referral.completed',
  'bonus.granted',
  'lead.created',
  'broadcast.completed',
  'scenario.completed',
] as const;

export type TgBotEventType = (typeof TG_BOT_EVENTS)[number];

@Injectable()
export class BotWebhookService {
  private readonly logger = new Logger(BotWebhookService.name);

  constructor(
    private readonly prisma: PrismaService,
    @InjectQueue('telegram-bot-webhook')
    private readonly webhookQueue: Queue,
  ) {}

  async create(clubId: string, botId: string, data: { url: string; events: string[] }) {
    const secret = randomBytes(32).toString('hex');

    return this.prisma.tgBotWebhook.create({
      data: {
        clubId,
        botId,
        url: data.url,
        secret,
        events: data.events,
      },
    });
  }

  async findAll(botId: string) {
    return this.prisma.tgBotWebhook.findMany({
      where: { botId },
      orderBy: { createdAt: 'desc' },
      select: {
        id: true,
        botId: true,
        url: true,
        events: true,
        isActive: true,
        createdAt: true,
      },
    });
  }

  async update(
    id: string,
    botId: string,
    data: { url?: string; events?: string[]; isActive?: boolean },
  ) {
    const webhook = await this.prisma.tgBotWebhook.findFirst({ where: { id, botId } });
    if (!webhook) throw new NotFoundException('Webhook not found');

    return this.prisma.tgBotWebhook.update({
      where: { id },
      data: {
        ...(data.url && { url: data.url }),
        ...(data.events && { events: data.events }),
        ...(data.isActive !== undefined && { isActive: data.isActive }),
      },
    });
  }

  async remove(id: string, botId: string) {
    const webhook = await this.prisma.tgBotWebhook.findFirst({ where: { id, botId } });
    if (!webhook) throw new NotFoundException('Webhook not found');
    await this.prisma.tgBotWebhook.delete({ where: { id } });
    return { deleted: true };
  }

  async test(id: string, botId: string) {
    const webhook = await this.prisma.tgBotWebhook.findFirst({ where: { id, botId } });
    if (!webhook) throw new NotFoundException('Webhook not found');

    await this.dispatch(botId, 'subscriber.created', {
      test: true,
      subscriber: { id: 'test-id', chatId: '12345', firstName: 'Test User' },
    });

    return { sent: true };
  }

  /**
   * Dispatch an event to all active webhook subscriptions for a bot.
   */
  async dispatch(
    botId: string,
    event: TgBotEventType,
    data: Record<string, unknown>,
  ): Promise<void> {
    const webhooks = await this.prisma.tgBotWebhook.findMany({
      where: { botId, isActive: true, events: { has: event } },
    });

    for (const webhook of webhooks) {
      const payload = {
        event,
        timestamp: new Date().toISOString(),
        bot_id: botId,
        data,
      };

      const body = JSON.stringify(payload);
      const signature = createHmac('sha256', webhook.secret).update(body).digest('hex');

      await this.webhookQueue.add(
        'deliver',
        {
          url: webhook.url,
          method: 'POST',
          body: payload,
          headers: {
            'X-TgBot-Signature': signature,
            'X-TgBot-Event': event,
          },
        },
        {
          attempts: 3,
          backoff: { type: 'exponential', delay: 5000 },
          removeOnComplete: 100,
          removeOnFail: 500,
        },
      );
    }
  }
}
