import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { UpsertConfigMoraDto } from './dto/config-mora.dto';

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

  async getOrCreate(empresa_id: string) {
    return this.prisma.config_mora.upsert({
      where: { empresa_id },
      create: { empresa_id },
      update: {},
    });
  }

  async upsert(empresa_id: string, dto: UpsertConfigMoraDto) {
    return this.prisma.config_mora.upsert({
      where: { empresa_id },
      create: {
        empresa_id,
        activo: dto.activo,
        tipo_calculo: dto.tipo_calculo,
        tasa: dto.tasa,
        base_calculo: dto.base_calculo,
        periodo_gracia: dto.periodo_gracia,
        monto_minimo_mora: dto.monto_minimo_mora,
        monto_maximo_mora: dto.monto_maximo_mora ?? null,
        descripcion_concepto: dto.descripcion_concepto,
      },
      update: {
        activo: dto.activo,
        tipo_calculo: dto.tipo_calculo,
        tasa: dto.tasa,
        base_calculo: dto.base_calculo,
        periodo_gracia: dto.periodo_gracia,
        monto_minimo_mora: dto.monto_minimo_mora,
        monto_maximo_mora: dto.monto_maximo_mora ?? null,
        descripcion_concepto: dto.descripcion_concepto,
        updated_at: new Date(),
      },
    });
  }

  /**
   * Calcula la mora para una cuota vencida.
   * @param saldoCuota - saldo pendiente de la cuota (capital o cuota completa según config)
   * @param montoCuotaCompleta - monto original de la cuota (para base_calculo = cuota_completa)
   * @param fechaVencimiento - fecha de vencimiento de la cuota
   * @param config - configuración de mora de la empresa
   * @returns monto de mora calculado (0 si no aplica)
   */
  calcularMora(
    saldoCuota: number,
    montoCuotaCompleta: number,
    fechaVencimiento: Date,
    config: {
      activo: boolean;
      tipo_calculo: string;
      tasa: number;
      base_calculo: string;
      periodo_gracia: number;
      monto_minimo_mora: number;
      monto_maximo_mora: number | null;
    },
  ): number {
    if (!config.activo || Number(config.tasa) === 0) return 0;

    const hoy = new Date();
    hoy.setHours(0, 0, 0, 0);
    const venc = new Date(fechaVencimiento);
    venc.setHours(0, 0, 0, 0);

    if (venc >= hoy) return 0; // no vencida

    const diasMora = Math.floor((hoy.getTime() - venc.getTime()) / (1000 * 60 * 60 * 24));
    const diasEfectivos = diasMora - config.periodo_gracia;
    if (diasEfectivos <= 0) return 0;

    const base = config.base_calculo === 'cuota_completa' ? montoCuotaCompleta : saldoCuota;
    const tasa = Number(config.tasa);
    let mora = 0;

    if (config.tipo_calculo === 'diario') {
      mora = base * (tasa / 100) * diasEfectivos;
    } else if (config.tipo_calculo === 'mensual') {
      // Prorrateo por días, no redondeo hacia arriba al mes. Esto coincide con el
      // preview de distribución del cobro (cobros.service.ts::calcularMoraCuota)
      // y evita que el recibo muestre Gs 517 mientras la factura de mora se
      // emitía por Gs 1.100 (ceil(31/30)=2 → cobraba 2 meses por 1 día extra).
      mora = base * (tasa / 100) * (diasEfectivos / 30);
    } else if (config.tipo_calculo === 'fijo_por_cuota') {
      mora = tasa; // monto fijo
    }

    mora = Math.round(mora);

    const minMora = Number(config.monto_minimo_mora);
    const maxMora = config.monto_maximo_mora ? Number(config.monto_maximo_mora) : null;

    if (minMora > 0 && mora < minMora) mora = minMora;
    if (maxMora !== null && mora > maxMora) mora = maxMora;

    return mora;
  }
}
