import { BadRequestException, GoneException, Injectable, NotFoundException } from '@nestjs/common';
import * as crypto from 'crypto';
import { $Enums } from '@prisma/client';
import { PrismaService } from 'src/prisma/prisma.service';

const EXPIRACION_DIAS = Number(process.env.PAGO_LINK_EXPIRACION_DIAS ?? 7);

@Injectable()
export class PagoLinkService {
  constructor(private readonly prisma: PrismaService) {}

  async crear(params: {
    empresaId: string;
    origenModulo: $Enums.bancard_origen_modulo;
    origenId: string;
    montoTotal: number;
    moneda?: string;
  }) {
    const { empresaId, origenModulo, origenId, montoTotal, moneda = 'PYG' } = params;

    // Invalidar links activos previos del mismo origen
    await this.prisma.pago_link.updateMany({
      where: { origen_modulo: origenModulo, origen_id: origenId, estado: $Enums.pago_link_estado.activo },
      data:  { estado: $Enums.pago_link_estado.cancelado, updated_at: new Date() },
    });

    const token = crypto.randomBytes(32).toString('base64url');
    const fechaExpiracion = new Date();
    fechaExpiracion.setDate(fechaExpiracion.getDate() + EXPIRACION_DIAS);

    return this.prisma.pago_link.create({
      data: {
        empresa_id:      empresaId,
        token,
        origen_modulo:   origenModulo,
        origen_id:       origenId,
        monto_total:     montoTotal,
        moneda,
        fecha_expiracion: fechaExpiracion,
      },
    });
  }

  async findByToken(token: string) {
    const link = await this.prisma.pago_link.findUnique({ where: { token } });
    if (!link) throw new NotFoundException('Link de pago no encontrado');

    if (link.estado === $Enums.pago_link_estado.pagado)    throw new BadRequestException('Este pago ya fue realizado');
    if (link.estado === $Enums.pago_link_estado.cancelado) throw new GoneException('Este link fue cancelado');

    if (link.estado === $Enums.pago_link_estado.activo && new Date() > link.fecha_expiracion) {
      await this.prisma.pago_link.update({
        where: { id: link.id },
        data:  { estado: $Enums.pago_link_estado.expirado, updated_at: new Date() },
      });
      throw new GoneException('El link de pago expiró');
    }

    if (link.estado === $Enums.pago_link_estado.expirado) throw new GoneException('El link de pago expiró');

    return link;
  }

  async marcarPagado(id: string, pagoBancardId: string) {
    return this.prisma.pago_link.update({
      where: { id },
      data:  { estado: $Enums.pago_link_estado.pagado, pago_bancard_id: pagoBancardId, updated_at: new Date() },
    });
  }
}
