/**
 * Resumen consolidado de presupuestos (pedido DOBA, oct-2026: "elijo el vendedor y me
 * junta todos sus presupuestos, con el total por cliente y la carga por producto").
 *
 * Es un reporte estándar, no la planilla del cliente: por producto (cantidad, equivalencia
 * en su empaque, monto, precio promedio y, con permiso, costo y margen), por cliente, y un
 * detalle plano para que cada empresa arme su propia tabla dinámica.
 *
 * Las cantidades de los presupuestos están en la unidad del producto. El empaque sale de la
 * presentación del producto (la por defecto, si no la primera; Caja x24 → 120 unidades =
 * 5 cajas); sin presentación sólo se informan unidades.
 */

export type ItemResumen = {
  tipo: string;
  producto_id: string | null;
  descripcion: string;
  cantidad: number;
  unidad_medida: string | null;
  precio_unitario: number;
  /** Total de la línea, IVA incluido (el precio del presupuesto ya lo incluye). */
  total: number;
};

export type PresupuestoResumen = {
  id: string;
  numero: string;
  fecha: string | null;
  estado: string;
  moneda: string;
  cliente: { id: string | null; nombre: string; documento: string | null };
  vendedor: string | null;
  items: ItemResumen[];
};

export type ProductoInfo = {
  id: string;
  codigo: string | null;
  descripcion: string;
  costo: number | null;
  empaque: { nombre: string; factor: number } | null;
};

/** Ítems que suman cantidad y monto; subtítulos y descuentos globales no son mercadería. */
const TIPOS_QUE_SUMAN = new Set(['PRODUCTO', 'SERVICIO', 'TEXTO_LIBRE']);

const r2 = (n: number) => Math.round((n + Number.EPSILON) * 100) / 100;

export function armarResumen(
  presupuestos: PresupuestoResumen[],
  productos: Map<string, ProductoInfo>,
  opciones: { verCosto: boolean },
) {
  const porProducto = new Map<string, any>();
  const porCliente = new Map<string, any>();
  const totales = new Map<string, { moneda: string; monto: number }>();
  const detalle: any[] = [];

  for (const p of presupuestos) {
    const claveCliente = `${p.cliente.id ?? p.cliente.nombre}|${p.moneda}`;
    const cli =
      porCliente.get(claveCliente) ??
      porCliente
        .set(claveCliente, {
          cliente_id: p.cliente.id,
          cliente: p.cliente.nombre,
          documento: p.cliente.documento,
          moneda: p.moneda,
          presupuestos: [] as string[],
          productos: new Set<string>(),
          cantidad: 0,
          monto: 0,
        })
        .get(claveCliente);
    cli.presupuestos.push(p.numero);

    for (const it of p.items) {
      if (!TIPOS_QUE_SUMAN.has(it.tipo)) continue;
      const info = it.producto_id ? productos.get(it.producto_id) : undefined;
      const clave = `${it.producto_id ?? `libre:${it.descripcion.trim().toUpperCase()}`}|${p.moneda}`;
      const prod =
        porProducto.get(clave) ??
        porProducto
          .set(clave, {
            producto_id: it.producto_id,
            codigo: info?.codigo ?? null,
            descripcion: info?.descripcion ?? it.descripcion,
            unidad_medida: it.unidad_medida,
            moneda: p.moneda,
            empaque: info?.empaque ?? null,
            costo_unitario: info?.costo ?? null,
            cantidad: 0,
            monto: 0,
            clientes: new Set<string>(),
          })
          .get(clave);
      prod.cantidad += it.cantidad;
      prod.monto += it.total;
      prod.clientes.add(claveCliente);

      cli.productos.add(clave);
      cli.cantidad += it.cantidad;
      cli.monto += it.total;

      const tot = totales.get(p.moneda) ?? totales.set(p.moneda, { moneda: p.moneda, monto: 0 }).get(p.moneda)!;
      tot.monto += it.total;

      detalle.push({
        presupuesto: p.numero,
        fecha: p.fecha,
        estado: p.estado,
        cliente: p.cliente.nombre,
        documento: p.cliente.documento,
        vendedor: p.vendedor,
        codigo: info?.codigo ?? null,
        producto: info?.descripcion ?? it.descripcion,
        cantidad: it.cantidad,
        unidad_medida: it.unidad_medida,
        empaques: info?.empaque ? r2(it.cantidad / info.empaque.factor) : null,
        precio_unitario: it.precio_unitario,
        total: r2(it.total),
        moneda: p.moneda,
      });
    }
  }

  const productosOut = [...porProducto.values()]
    .map((x) => {
      const precioPromedio = x.cantidad > 0 ? x.monto / x.cantidad : 0;
      // El costo del producto está en guaraníes: sólo se compara contra precios en guaraníes.
      const costo = opciones.verCosto && x.moneda === 'PYG' && x.costo_unitario ? x.costo_unitario : null;
      return {
        producto_id: x.producto_id,
        codigo: x.codigo,
        descripcion: x.descripcion,
        unidad_medida: x.unidad_medida,
        moneda: x.moneda,
        cantidad: r2(x.cantidad),
        empaque: x.empaque,
        empaques: x.empaque ? r2(x.cantidad / x.empaque.factor) : null,
        monto: r2(x.monto),
        precio_promedio: r2(precioPromedio),
        clientes: x.clientes.size,
        ...(opciones.verCosto
          ? {
              costo_unitario: costo,
              costo_total: costo != null ? r2(costo * x.cantidad) : null,
              // Misma fórmula que usan los clientes en sus planillas: sobre el precio de venta.
              margen_pct: costo != null && precioPromedio > 0 ? r2(((precioPromedio - costo) / precioPromedio) * 100) : null,
            }
          : {}),
      };
    })
    .sort((a, b) => b.monto - a.monto);

  const clientesOut = [...porCliente.values()]
    .map((c) => ({
      cliente_id: c.cliente_id,
      cliente: c.cliente,
      documento: c.documento,
      moneda: c.moneda,
      presupuestos: c.presupuestos,
      productos: c.productos.size,
      cantidad: r2(c.cantidad),
      monto: r2(c.monto),
    }))
    .sort((a, b) => b.monto - a.monto);

  return {
    totales: {
      presupuestos: presupuestos.length,
      clientes: new Set(presupuestos.map((p) => p.cliente.id ?? p.cliente.nombre)).size,
      productos: productosOut.length,
      cantidad: r2(productosOut.reduce((a, x) => a + x.cantidad, 0)),
      montos: [...totales.values()].map((t) => ({ moneda: t.moneda, monto: r2(t.monto) })),
    },
    por_producto: productosOut,
    por_cliente: clientesOut,
    detalle,
    ver_costo: opciones.verCosto,
  };
}
