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 OneCConfig {
  baseUrl: string;
  username: string;
  password: string;
  catalogId?: string;
}

interface OneCRecordData {
  id: string;
  number: number;
  clientName: string;
  clientPhone?: string;
  startAt: string | Date;
  endAt: string | Date;
  price?: number | string;
  service?: { name: string } | null;
  staff?: { firstName: string; lastName: string } | null;
}

interface OneCPaymentData {
  id: string;
  recordId: string;
  amount: number | string;
  method: string;
  paidAt?: string;
}

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

function extractPayment(data: Record<string, unknown>): OneCPaymentData {
  return data['payment'] as OneCPaymentData;
}

@Injectable()
export class OneCAdapter {
  private readonly logger = new Logger(OneCAdapter.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);
    const source = (payload.data['source'] as string) ?? 'ADMIN';

    await this.send(config, '/documents/booking', 'POST', {
      Ref: record.id,
      Number: record.number,
      Date: record.startAt,
      ClientName: record.clientName,
      ClientPhone: record.clientPhone ?? '',
      ServiceName: record.service?.name ?? '',
      StaffName: record.staff ? `${record.staff.lastName} ${record.staff.firstName}` : '',
      StartAt: record.startAt,
      EndAt: record.endAt,
      Price: record.price ?? 0,
      Status: 'New',
      Source: source,
    });
  }

  @OnEvent('booking.record.confirmed', { async: true })
  async onStatusChange(payload: BookingEventPayload) {
    await this.updateStatus(payload, 'Confirmed');
  }

  @OnEvent('booking.record.completed', { async: true })
  async onCompleted(payload: BookingEventPayload) {
    await this.updateStatus(payload, 'Completed');
  }

  @OnEvent('booking.record.cancelled', { async: true })
  async onCancelled(payload: BookingEventPayload) {
    await this.updateStatus(payload, 'Cancelled');
  }

  @OnEvent('booking.record.noshow', { async: true })
  async onNoShow(payload: BookingEventPayload) {
    await this.updateStatus(payload, 'NoShow');
  }

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

    const payment = extractPayment(payload.data);

    await this.send(config, '/documents/payment', 'POST', {
      Ref: payment.id,
      BookingRef: payment.recordId,
      Amount: payment.amount,
      Method: payment.method,
      Date: payment.paidAt ?? new Date().toISOString(),
    });
  }

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

  private async updateStatus(payload: BookingEventPayload, status: string) {
    const config = await this.getConfig(payload.clubId);
    if (!config) return;

    const record = extractRecord(payload.data);

    await this.send(config, `/documents/booking/${record.id}/status`, 'PATCH', {
      Status: status,
      UpdatedAt: new Date().toISOString(),
    });
  }

  private async getConfig(clubId: string): Promise<OneCConfig | 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'] !== '1c' || !meta?.['onec']) return null;

    return meta['onec'] as OneCConfig;
  }

  private async send(
    config: OneCConfig,
    path: string,
    method: string,
    body: Record<string, unknown>,
  ) {
    const url = `${config.baseUrl.replace(/\/$/, '')}${path}`;
    const auth = Buffer.from(`${config.username}:${config.password}`).toString('base64');

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

      if (!response.ok) {
        this.logger.warn(`1C ${method} ${path} failed: HTTP ${response.status}`);
      }

      return response.ok;
    } catch (error) {
      const msg = error instanceof Error ? error.message : String(error);
      this.logger.error(`1C ${method} ${path} error: ${msg}`);
      return false;
    }
  }
}
