import { Injectable, Logger } from '@nestjs/common';
import { OnEvent } from '@nestjs/event-emitter';
import { PrismaService } from '../../../prisma/prisma.service';
import { BookingEventPayload } from '../core/booking-events.service';

interface CrmRecordData {
  id: string;
  number: number;
  clientId?: string | null;
  clientName?: string;
  clientPhone?: string;
  clientEmail?: string | null;
  startAt: string | Date;
  price?: number | string;
  service?: { name: string } | null;
}

function extractRecord(data: Record<string, unknown>): CrmRecordData {
  return data['record'] as CrmRecordData;
}

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

  constructor(private readonly prisma: PrismaService) {}

  @OnEvent('booking.record.created', { async: true })
  async onRecordCreated(payload: BookingEventPayload) {
    const bridge = await this.prisma.bookingCrmBridge.findUnique({
      where: { clubId: payload.clubId },
    });

    if (!bridge?.isEnabled || !bridge.createDealOnBook || !bridge.pipelineId) return;

    const stageId = bridge.newRecordStageId;
    if (!stageId) return;

    const record = extractRecord(payload.data);

    try {
      let clientId = record.clientId;
      const meta = bridge.metadata as Record<string, unknown> | null;

      if (!clientId && meta?.['autoCreateClient'] && record.clientPhone) {
        const existing = await this.prisma.client.findFirst({
          where: { clubId: payload.clubId, phone: record.clientPhone },
          select: { id: true },
        });

        if (existing) {
          clientId = existing.id;
        } else {
          const client = await this.prisma.client.create({
            data: {
              clubId: payload.clubId,
              firstName: record.clientName?.split(' ')[0] ?? 'Клиент',
              lastName: record.clientName?.split(' ').slice(1).join(' ') || '',
              phone: record.clientPhone,
              email: record.clientEmail,
              source: 'BOOKING',
            },
          });
          clientId = client.id;

          await this.prisma.bookingRecord.update({
            where: { id: record.id },
            data: { clientId },
          });
        }
      }

      const lastDeal = await this.prisma.crmDeal.findFirst({
        where: { clubId: payload.clubId },
        orderBy: { number: 'desc' },
        select: { number: true },
      });

      const deal = await this.prisma.crmDeal.create({
        data: {
          clubId: payload.clubId,
          pipelineId: bridge.pipelineId,
          stageId,
          number: (lastDeal?.number ?? 0) + 1,
          title: `Запись #${record.number}: ${record.clientName ?? 'Новая запись'}`,
          contactName: record.clientName ?? 'Клиент',
          contactPhone: record.clientPhone,
          contactEmail: record.clientEmail,
          amount: record.price,
          metadata: {
            bookingRecordId: record.id,
            bookingService: record.service?.name,
            bookingDate: record.startAt,
            source: 'booking_module',
          },
        },
      });

      this.logger.log(`CRM deal #${deal.number} created from booking #${record.number}`);
    } catch (error) {
      const msg = error instanceof Error ? error.message : String(error);
      this.logger.error(`CRM bridge failed for record ${record.id}: ${msg}`);
    }
  }

  @OnEvent('booking.record.confirmed', { async: true })
  async onConfirmed(payload: BookingEventPayload) {
    const bridge = await this.prisma.bookingCrmBridge.findUnique({
      where: { clubId: payload.clubId },
    });
    if (!bridge?.isEnabled) return;

    const meta = bridge.metadata as Record<string, unknown> | null;
    const stageId = meta?.['confirmedStageId'] as string | undefined;
    if (stageId) await this.moveDeal(payload, bridge.pipelineId!, stageId);
  }

  @OnEvent('booking.record.completed', { async: true })
  async onCompleted(payload: BookingEventPayload) {
    const bridge = await this.prisma.bookingCrmBridge.findUnique({
      where: { clubId: payload.clubId },
    });
    if (!bridge?.isEnabled || !bridge.completedStageId) return;

    await this.moveDeal(payload, bridge.pipelineId!, bridge.completedStageId);
  }

  @OnEvent('booking.record.cancelled', { async: true })
  async onCancelled(payload: BookingEventPayload) {
    const bridge = await this.prisma.bookingCrmBridge.findUnique({
      where: { clubId: payload.clubId },
    });
    if (!bridge?.isEnabled || !bridge.cancelledStageId) return;

    await this.moveDeal(payload, bridge.pipelineId!, bridge.cancelledStageId);
  }

  @OnEvent('booking.record.noshow', { async: true })
  async onNoShow(payload: BookingEventPayload) {
    const bridge = await this.prisma.bookingCrmBridge.findUnique({
      where: { clubId: payload.clubId },
    });
    if (!bridge?.isEnabled) return;

    const meta = bridge.metadata as Record<string, unknown> | null;
    const stageId = (meta?.['noShowStageId'] as string) ?? bridge.cancelledStageId;
    if (stageId) await this.moveDeal(payload, bridge.pipelineId!, stageId);
  }

  // ─── Helpers ─────────────────────────────────────────────

  private async moveDeal(payload: BookingEventPayload, pipelineId: string, stageId: string) {
    const record = extractRecord(payload.data);

    try {
      const deals = await this.prisma.crmDeal.findMany({
        where: {
          clubId: payload.clubId,
          pipelineId,
          metadata: { path: ['bookingRecordId'], equals: record.id },
        },
        take: 1,
      });

      if (deals.length === 0) return;

      await this.prisma.crmDeal.update({
        where: { id: deals[0].id },
        data: { stageId },
      });

      this.logger.log(`CRM deal #${deals[0].number} moved to stage ${stageId}`);
    } catch (error) {
      const msg = error instanceof Error ? error.message : String(error);
      this.logger.error(`CRM bridge stage update failed: ${msg}`);
    }
  }
}
