import type { PrismaService } from 'src/prisma/prisma.service';

/**
 * Foto legible de un asiento para la auditoría: qué número tenía, en qué
 * período, por cuánto y contra qué cuentas. Rehacer o regenerar asientos cambia
 * la contabilidad sin que nadie tipee nada; sin esto, el log solo decía
 * "asiento regenerado (doc 2789062b)" y no había forma de saber qué pasó.
 */
export interface FotoAsiento {
  asiento_id: string;
  numero: number;
  fecha: string;
  periodo: string;
  glosa: string | null;
  documento: string | null;
  total: number;
  lineas: { cuenta: string; descripcion: string | null; debe: number; haber: number }[];
}

const fmt = (n: number) => Math.round(n).toLocaleString('es-PY');

export async function fotoAsiento(prisma: PrismaService, asientoId: string): Promise<FotoAsiento | null> {
  const a = await prisma.cont_asientos.findUnique({
    where: { id: asientoId },
    select: {
      id: true,
      numero: true,
      fecha: true,
      glosa: true,
      total_debe_pyg: true,
      periodo: { select: { mes: true, anio: true } },
      documento: { select: { numero_documento: true } },
      lineas: {
        orderBy: { orden: 'asc' },
        select: { debe_pyg: true, haber_pyg: true, descripcion: true, cuenta: { select: { codigo: true, descripcion: true } } },
      },
    },
  });
  if (!a) return null;
  return {
    asiento_id: a.id,
    numero: a.numero,
    fecha: a.fecha.toISOString().slice(0, 10),
    periodo: a.periodo ? `${a.periodo.mes}/${a.periodo.anio}` : '',
    glosa: a.glosa,
    documento: a.documento?.numero_documento ?? null,
    total: Number(a.total_debe_pyg),
    lineas: a.lineas.map((l) => ({
      cuenta: l.cuenta ? `${l.cuenta.codigo} ${l.cuenta.descripcion}` : '?',
      descripcion: l.descripcion,
      debe: Number(l.debe_pyg),
      haber: Number(l.haber_pyg),
    })),
  };
}

export async function fotoAsientoDeDocumento(prisma: PrismaService, documentoId: string): Promise<FotoAsiento | null> {
  const a = await prisma.cont_asientos.findFirst({ where: { documento_id: documentoId }, select: { id: true } });
  return a ? fotoAsiento(prisma, a.id) : null;
}

/**
 * Cuentas cuyo neto (debe − haber) cambió entre dos asientos, en texto:
 * "1.01.01.02 RECAUDACIONES EFECTIVO: 500.000 → 0; 1.01.01.01 CAJA: 0 → 500.000".
 */
export function cuentasQueCambian(antes: FotoAsiento | null, despues: FotoAsiento | null): { cuenta: string; antes: number; despues: number }[] {
  const neto = (f: FotoAsiento | null) => {
    const m = new Map<string, number>();
    for (const l of f?.lineas ?? []) m.set(l.cuenta, (m.get(l.cuenta) ?? 0) + l.debe - l.haber);
    return m;
  };
  const a = neto(antes);
  const d = neto(despues);
  const cuentas = [...new Set([...a.keys(), ...d.keys()])].sort();
  return cuentas
    .map((c) => ({ cuenta: c, antes: Math.round((a.get(c) ?? 0) * 100) / 100, despues: Math.round((d.get(c) ?? 0) * 100) / 100 }))
    .filter((x) => Math.abs(x.antes - x.despues) >= 0.5);
}

export function textoCambios(cambios: { cuenta: string; antes: number; despues: number }[], max = 6): string {
  if (!cambios.length) return 'Sin cambios de cuentas ni montos (solo se rehízo el asiento).';
  const partes = cambios.slice(0, max).map((c) => `${c.cuenta}: ${fmt(c.antes)} → ${fmt(c.despues)}`);
  const resto = cambios.length > max ? ` (y ${cambios.length - max} cuenta(s) más)` : '';
  return `Cambian: ${partes.join('; ')}${resto}.`;
}

export const describirAsiento = (f: FotoAsiento | null) =>
  f ? `N° ${f.numero} (${f.periodo}, Gs. ${fmt(f.total)})` : '(sin asiento)';

/** Líneas en una frase: "Cuentas: 1.01.01.01 CAJA debe 100.000; 4.01.01 VENTAS haber 100.000". */
export function textoLineas(f: FotoAsiento | null, max = 8): string {
  if (!f?.lineas.length) return '';
  const partes = f.lineas
    .slice(0, max)
    .map((l) => `${l.cuenta} ${l.debe ? `debe ${fmt(l.debe)}` : `haber ${fmt(l.haber)}`}`);
  const resto = f.lineas.length > max ? ` (y ${f.lineas.length - max} línea(s) más)` : '';
  return `Cuentas: ${partes.join('; ')}${resto}.`;
}

/** Cambios de fecha y glosa entre dos fotos del mismo asiento, en texto (vacío si no cambian). */
export function cambiosDeCabecera(antes: FotoAsiento | null, despues: FotoAsiento | null): string {
  const partes: string[] = [];
  if (antes && despues && antes.fecha !== despues.fecha) partes.push(`Fecha: ${antes.fecha} → ${despues.fecha}`);
  if (antes && despues && (antes.glosa ?? '') !== (despues.glosa ?? '')) partes.push(`Glosa: "${antes.glosa ?? ''}" → "${despues.glosa ?? ''}"`);
  return partes.length ? `${partes.join('. ')}. ` : '';
}
