/**
 * Reglas de debida diligencia (Ley 1015/97, Res. SEPRELAD 201/2020). Funciones puras
 * para testearlas solas. Son el mínimo que pide el spec (M123); el oficial de
 * cumplimiento puede subir el riesgo a mano, nunca bajarlo de lo calculado.
 */

export type NivelRiesgo = 'BAJO' | 'MEDIO' | 'ALTO';
export const ORDEN_RIESGO: Record<NivelRiesgo, number> = { BAJO: 0, MEDIO: 1, ALTO: 2 };

export interface BeneficiarioFinal {
  nombre: string;
  documento?: string | null;
  pct: number;
  pep?: boolean;
}

/** Participación desde la que una persona es beneficiario final (criterio SEPRELAD habitual). */
export const PCT_BENEFICIARIO_FINAL = 10;

export interface DatosLegajo {
  tipo_persona: 'FISICA' | 'JURIDICA';
  actividad?: string | null;
  origen_fondos?: string | null;
  pep: boolean;
  beneficiarios_finales: BeneficiarioFinal[];
}

/** Riesgo mínimo según los datos y los antecedentes del cliente. */
export function calcularRiesgo(
  l: DatosLegajo,
  antecedentes: { inusuales_reportadas: number; inusuales_abiertas: number },
) {
  if (l.pep || l.beneficiarios_finales.some((b) => b.pep)) return 'ALTO' as NivelRiesgo;
  if (antecedentes.inusuales_reportadas > 0) return 'ALTO' as NivelRiesgo;
  if (antecedentes.inusuales_abiertas > 0) return 'MEDIO' as NivelRiesgo;
  if (l.tipo_persona === 'JURIDICA') return 'MEDIO' as NivelRiesgo;
  return 'BAJO' as NivelRiesgo;
}

/** El riesgo final: el pedido, pero nunca menor al calculado. */
export const riesgoFinal = (calculado: NivelRiesgo, pedido?: NivelRiesgo | null) =>
  pedido && ORDEN_RIESGO[pedido] > ORDEN_RIESGO[calculado] ? pedido : calculado;

/** Qué le falta al legajo para poder aprobarse. Vacío = se puede aprobar. */
export function faltantesParaAprobar(l: DatosLegajo, documentos: Array<{ tipo: string; anulado: boolean }>) {
  const vigentes = new Set(documentos.filter((d) => !d.anulado).map((d) => d.tipo));
  const f: string[] = [];
  if (!l.actividad?.trim()) f.push('la actividad o profesión');
  if (!l.origen_fondos?.trim()) f.push('el origen de los fondos');
  if (!vigentes.has('CEDULA') && !vigentes.has('RUC')) f.push('la copia de la cédula o del RUC');
  if (l.tipo_persona === 'JURIDICA') {
    if (!l.beneficiarios_finales.some((b) => b.nombre?.trim() && b.pct >= PCT_BENEFICIARIO_FINAL))
      f.push(`al menos un beneficiario final (persona física con ${PCT_BENEFICIARIO_FINAL} % o más)`);
    if (!vigentes.has('ESTATUTO')) f.push('el estatuto de la sociedad');
  }
  if ((l.pep || l.beneficiarios_finales.some((b) => b.pep)) && !vigentes.has('DECLARACION_PEP'))
    f.push('la declaración jurada de PEP');
  const suma = l.beneficiarios_finales.reduce((a, b) => a + (Number(b.pct) || 0), 0);
  if (suma > 100.0001) f.push('que los beneficiarios finales no sumen más del 100 %');
  return f;
}

/** ¿El legajo habilita operar hoy? (aprobado y sin vencer) */
export function vigenciaLegajo(
  l: { estado: string; vence: Date | string | null } | null,
  hoy: string,
): { vigente: boolean; motivo: string | null } {
  if (!l) return { vigente: false, motivo: 'no tiene legajo de debida diligencia' };
  if (l.estado === 'OBSERVADO') return { vigente: false, motivo: 'su legajo está observado' };
  if (l.estado !== 'APROBADO') return { vigente: false, motivo: 'su legajo no está aprobado' };
  const vence = l.vence ? (typeof l.vence === 'string' ? l.vence : l.vence.toISOString()).slice(0, 10) : null;
  if (vence && vence < hoy) return { vigente: false, motivo: `su legajo venció el ${vence}` };
  return { vigente: true, motivo: null };
}

/**
 * Fraccionamiento: clientes cuyos pagos en efectivo de la ventana suman el umbral o
 * más sin que ninguno solo lo alcance (los que lo alcanzan ya tienen su alerta propia).
 */
export function detectarFraccionamiento(
  cobros: Array<{ cliente_id: string; monto_gs: number }>,
  umbral: number,
): Array<{ cliente_id: string; total: number; cantidad: number }> {
  const por = new Map<string, { total: number; cantidad: number; max: number }>();
  for (const c of cobros) {
    const a = por.get(c.cliente_id) ?? { total: 0, cantidad: 0, max: 0 };
    a.total += c.monto_gs;
    a.cantidad += 1;
    a.max = Math.max(a.max, c.monto_gs);
    por.set(c.cliente_id, a);
  }
  return [...por]
    .filter(([, a]) => a.cantidad > 1 && a.total >= umbral && a.max < umbral)
    .map(([cliente_id, a]) => ({ cliente_id, total: Math.round(a.total), cantidad: a.cantidad }));
}

/** Hasta cuándo hay que conservar el legajo: 5 años desde la última operación o cobro. */
export function conservarHasta(ultimaActividad: string | null): string | null {
  if (!ultimaActividad) return null;
  const d = new Date(`${ultimaActividad.slice(0, 10)}T00:00:00.000Z`);
  d.setUTCFullYear(d.getUTCFullYear() + 5);
  return d.toISOString().slice(0, 10);
}
