import { Injectable, Logger } from '@nestjs/common';
import { ecommerce_checkout_estado } from '@prisma/client';
import { PrismaService } from 'src/prisma/prisma.service';
import { EcommerceNotificationsService } from '../notifications/ecommerce-notifications.service';
import { EcommerceStockReservaService } from '../stock/ecommerce-stock-reserva.service';

/**
 * Compra en cuotas de la tienda ↔ solicitud de crédito del ERP.
 *
 * El checkout crea la solicitud y la vincula a la sesión, pero después el pedido no se
 * enteraba de nada: facturada la solicitud seguía en «Pendiente pago» con el stock
 * reservado hasta expirar (marcándose «Expirado» con la factura ya emitida), y una
 * solicitud rechazada dejaba el pedido colgado. Acá se sincronizan los dos.
 */
@Injectable()
export class EcommerceCreditoService {
  private readonly logger = new Logger(EcommerceCreditoService.name);

  constructor(
    private readonly prisma: PrismaService,
    private readonly reservas: EcommerceStockReservaService,
    private readonly notifications: EcommerceNotificationsService,
  ) {}

  private async sesionDeSolicitud(empresaId: string, solicitudId: string) {
    return this.prisma.ecommerce_checkout_session.findFirst({
      where: { empresa_id: empresaId, solicitud_credito_id: solicitudId },
      select: { id: true, codigo: true, estado: true, notas: true },
    });
  }

  private async cambiarEstado(
    s: { id: string; estado: ecommerce_checkout_estado; notas: string | null },
    empresaId: string,
    estado: ecommerce_checkout_estado,
    nota: string,
    metadata: Record<string, unknown>,
  ) {
    await this.prisma.ecommerce_checkout_session.update({
      where: { id: s.id },
      data: {
        estado,
        notas: s.notas ? `${s.notas}\n${nota}` : nota,
        ...(estado === 'pago_confirmado' ? { confirmado_at: new Date() } : {}),
        updated_at: new Date(),
      },
    });
    await this.prisma.ecommerce_pedido_evento.create({
      data: {
        empresa_id: empresaId,
        checkout_session_id: s.id,
        tipo: 'estado',
        estado_anterior: s.estado,
        estado_nuevo: estado,
        metadata: { origen: 'solicitud_credito', ...metadata },
      },
    });
  }

  /** Factura emitida desde la solicitud: el pedido sigue el circuito como pagado. */
  async onSolicitudFacturada(empresaId: string, solicitudId: string, facturaId: string): Promise<void> {
    const s = await this.sesionDeSolicitud(empresaId, solicitudId);
    if (!s) return;
    // El stock lo descuenta la factura: la reserva del checkout ya no corresponde.
    await this.reservas.liberar(s.id);
    if (s.estado === 'pendiente_pago' || s.estado === 'expirado') {
      await this.cambiarEstado(s, empresaId, 'pago_confirmado', 'Compra en cuotas: crédito aprobado y facturado.', {
        factura_id: facturaId,
      });
    }
    this.logger.log(`Pedido ${s.codigo}: solicitud de crédito facturada (${facturaId}).`);
    await this.notifications.onOrderInvoicedSesion(empresaId, s.id);
  }

  /** Solicitud rechazada o cancelada: el pedido se cancela y libera el stock. */
  async onSolicitudCerrada(empresaId: string, solicitudId: string, motivo: 'rechazada' | 'cancelada', detalle?: string) {
    const s = await this.sesionDeSolicitud(empresaId, solicitudId);
    if (!s || s.estado !== 'pendiente_pago') return;
    await this.reservas.liberar(s.id);
    await this.cambiarEstado(
      s,
      empresaId,
      'cancelado',
      `Compra en cuotas: la solicitud de crédito fue ${motivo}${detalle ? ` (${detalle})` : ''}.`,
      { motivo, detalle: detalle ?? null },
    );
    this.logger.log(`Pedido ${s.codigo}: cancelado porque la solicitud de crédito fue ${motivo}.`);
    await this.notifications.onOrderCancelled(empresaId, s.id);
  }
}
