import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Logger } from '@nestjs/common';
import { Job } from 'bullmq';
import { PrismaService } from '../../../prisma/prisma.service';
import { createHmac } from 'crypto';

export interface BookingWebhookJobData {
  endpointId: string;
  url: string;
  secret: string;
  event: string;
  payload: Record<string, unknown>;
  logId: string;
}

const RETRY_DELAYS = [60_000, 300_000, 1_800_000]; // 1min, 5min, 30min

@Processor('booking-webhooks')
export class BookingWebhookProcessor extends WorkerHost {
  private readonly logger = new Logger(BookingWebhookProcessor.name);

  constructor(private readonly prisma: PrismaService) {
    super();
  }

  async process(job: Job<BookingWebhookJobData>): Promise<void> {
    const { url, secret, event, payload, logId } = job.data;
    const attempt = job.attemptsMade + 1;

    this.logger.log(`Webhook delivery: event=${event} url=${url} attempt=${attempt}`);

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

    try {
      const response = await fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Booking-Event': event,
          'X-Booking-Signature': `sha256=${signature}`,
          'X-Booking-Delivery': logId,
          'User-Agent': 'MyFitBooking-Webhook/1.0',
        },
        body,
        signal: AbortSignal.timeout(10_000),
      });

      await this.prisma.bookingWebhookLog.update({
        where: { id: logId },
        data: {
          statusCode: response.status,
          response: (await response.text()).slice(0, 1000),
          attempts: attempt,
          nextRetry: null,
        },
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }

      this.logger.log(`Webhook delivered: event=${event} status=${response.status}`);
    } catch (error) {
      const msg = error instanceof Error ? error.message : String(error);
      this.logger.warn(`Webhook failed: event=${event} attempt=${attempt} error=${msg}`);

      const nextDelay = RETRY_DELAYS[attempt - 1];
      await this.prisma.bookingWebhookLog.update({
        where: { id: logId },
        data: {
          attempts: attempt,
          response: msg.slice(0, 1000),
          nextRetry: nextDelay ? new Date(Date.now() + nextDelay) : null,
        },
      });

      if (attempt < 3) {
        throw error; // BullMQ will retry
      }
      // Max attempts reached — don't throw, job is done
    }
  }
}
