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 Bitrix24Config {
  webhookUrl: string;
  dealCategoryId?: number;
  responsibleId?: number;
  sourceId?: string;
}

interface BookingRecordData {
  id: string;
  number: number;
  clientName: string;
  clientPhone: string;
  startAt: Date | string;
  notes?: string | null;
  service?: { name: string } | null;
}

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

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

  constructor(private readonly prisma: PrismaService) {}

  @OnEvent('booking.record.created', { async: true })
  async onRecordCreated(payload: BookingEventPayload) {
    const config = await this.getConfig(payload.clubId);
    if (!config) return;

    const record = extractRecord(payload.data);

    await this.callBitrix(config, 'crm.deal.add', {
      fields: {
        TITLE: `Запись #${record.number}: ${record.clientName}`,
        CATEGORY_ID: config.dealCategoryId ?? 0,
        RESPONSIBLE_ID: config.responsibleId,
        SOURCE_ID: config.sourceId ?? 'BOOKING',
        COMMENTS: this.buildComment(record),
        UF_BOOKING_ID: record.id,
        UF_BOOKING_SERVICE: record.service?.name,
        UF_BOOKING_DATE: record.startAt,
      },
    });
  }

  @OnEvent('booking.record.confirmed', { async: true })
  async onRecordConfirmed(payload: BookingEventPayload) {
    const config = await this.getConfig(payload.clubId);
    if (!config) return;

    const record = extractRecord(payload.data);
    const dealId = await this.findDealByBookingId(config, record.id);
    if (!dealId) return;

    await this.callBitrix(config, 'crm.deal.update', {
      id: dealId,
      fields: { STAGE_ID: 'PREPARATION' },
    });
  }

  @OnEvent('booking.record.completed', { async: true })
  async onRecordCompleted(payload: BookingEventPayload) {
    const config = await this.getConfig(payload.clubId);
    if (!config) return;

    const record = extractRecord(payload.data);
    const dealId = await this.findDealByBookingId(config, record.id);
    if (!dealId) return;

    await this.callBitrix(config, 'crm.deal.update', {
      id: dealId,
      fields: { STAGE_ID: 'WON' },
    });
  }

  @OnEvent('booking.record.cancelled', { async: true })
  async onRecordCancelled(payload: BookingEventPayload) {
    const config = await this.getConfig(payload.clubId);
    if (!config) return;

    const record = extractRecord(payload.data);
    const dealId = await this.findDealByBookingId(config, record.id);
    if (!dealId) return;

    await this.callBitrix(config, 'crm.deal.update', {
      id: dealId,
      fields: { STAGE_ID: 'LOSE' },
    });
  }

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

  private async getConfig(clubId: string): Promise<Bitrix24Config | null> {
    const bridge = await this.prisma.bookingCrmBridge.findUnique({
      where: { clubId },
    });

    if (!bridge?.isEnabled) return null;

    const meta = bridge.metadata as Record<string, unknown> | null;
    if (meta?.externalSystem !== 'bitrix24' || !meta?.bitrix24) return null;

    return meta.bitrix24 as Bitrix24Config;
  }

  private async callBitrix(
    config: Bitrix24Config,
    method: string,
    params: Record<string, unknown>,
  ): Promise<Record<string, unknown> | null> {
    const url = `${config.webhookUrl.replace(/\/$/, '')}/${method}.json`;

    try {
      const response = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(params),
        signal: AbortSignal.timeout(15_000),
      });

      if (!response.ok) {
        this.logger.warn(`Bitrix24 ${method} failed: HTTP ${response.status}`);
        return null;
      }

      return (await response.json()) as Record<string, unknown>;
    } catch (error) {
      const msg = error instanceof Error ? error.message : String(error);
      this.logger.error(`Bitrix24 ${method} error: ${msg}`);
      return null;
    }
  }

  private async findDealByBookingId(
    config: Bitrix24Config,
    bookingId: string,
  ): Promise<number | null> {
    const result = await this.callBitrix(config, 'crm.deal.list', {
      filter: { UF_BOOKING_ID: bookingId },
      select: ['ID'],
    });

    const items = result?.['result'];
    if (!Array.isArray(items) || items.length === 0) return null;
    return ((items[0] as Record<string, unknown>)['ID'] as number) ?? null;
  }

  private buildComment(record: BookingRecordData): string {
    const lines = [
      `Услуга: ${record.service?.name ?? '—'}`,
      `Дата: ${new Date(record.startAt).toLocaleString('ru-RU')}`,
      `Телефон: ${record.clientPhone ?? '—'}`,
    ];
    if (record.notes) lines.push(`Примечание: ${record.notes}`);
    return lines.join('\n');
  }
}
