/**
 * One-shot: completa `compra_cab.sucursal_id` en las compras que quedaron sin
 * sucursal.
 *
 * Por qué: el listado de compras ahora filtra por las sucursales asignadas al
 * usuario. Una compra sin sucursal no pertenece a ninguna, así que deja de
 * verse para todo el que no tenga acceso elevado — parece que se perdieron.
 *
 * Dos estrategias, en orden:
 *
 *   1. POR DEPÓSITO — la compra tiene `deposito_id` y el depósito sabe a qué
 *      sucursal pertenece. Es la buena: el dato sale del propio documento.
 *
 *   2. SUCURSAL ÚNICA — la compra no tiene depósito, pero la empresa tiene una
 *      sola sucursal activa, así que no hay ambigüedad posible. Se desactiva
 *      con --sin-fallback si preferís revisarlas a mano.
 *
 * Lo que no entra en ninguna de las dos se reporta y no se toca.
 *
 * Idempotente: sólo mira compras con `sucursal_id IS NULL`.
 *
 * Uso:
 *   pnpm exec ts-node scripts/backfill-compras-sucursal.ts [--empresa=<id>] [--sin-fallback] [--apply]
 *
 * Sin --apply → dry-run (default seguro).
 */
import 'dotenv/config';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

function parseArgs(argv: string[]) {
  const empresaArg = argv.find((a) => a.startsWith('--empresa='));
  return {
    apply: argv.includes('--apply'),
    sinFallback: argv.includes('--sin-fallback'),
    empresa: empresaArg ? empresaArg.split('=')[1] : undefined,
  };
}

async function main() {
  const args = parseArgs(process.argv.slice(2));

  const compras = await prisma.compra_cab.findMany({
    where: {
      sucursal_id: null,
      ...(args.empresa ? { empresa_id: args.empresa } : {}),
    },
    select: {
      id: true,
      empresa_id: true,
      numero_factura: true,
      fecha_emision: true,
      deposito_id: true,
      deposito: { select: { descripcion: true, sucursal_id: true } },
      empresas: { select: { razon_social: true } },
    },
    orderBy: { fecha_emision: 'asc' },
  });

  if (compras.length === 0) {
    console.log('\nNo hay compras sin sucursal. Nada que hacer.\n');
    await prisma.$disconnect();
    return;
  }
  console.log(`\nCompras sin sucursal: ${compras.length}\n`);

  // Sucursal única por empresa, para el fallback. Se resuelve una sola vez.
  const empresaIds = [...new Set(compras.map((c) => c.empresa_id))];
  const sucursales = await prisma.empresas_sucursales.findMany({
    where: { empresa_id: { in: empresaIds }, active: { not: false } },
    select: { id: true, empresa_id: true, descripcion: true },
  });
  const sucursalUnica = new Map<string, { id: string; descripcion: string }>();
  for (const id of empresaIds) {
    const propias = sucursales.filter((s) => s.empresa_id === id);
    if (propias.length === 1) sucursalUnica.set(id, propias[0]);
  }

  type Plan = { id: string; sucursalId: string; via: string; detalle: string };
  const plan: Plan[] = [];
  const sinResolver: string[] = [];

  for (const c of compras) {
    const etiqueta = `${c.empresas?.razon_social ?? '—'} | ${c.numero_factura ?? 's/nº'} | ${c.fecha_emision?.toISOString().slice(0, 10) ?? '—'}`;

    if (c.deposito?.sucursal_id) {
      plan.push({
        id: c.id,
        sucursalId: c.deposito.sucursal_id,
        via: 'POR DEPÓSITO',
        detalle: `${etiqueta} → depósito "${c.deposito.descripcion}"`,
      });
      continue;
    }

    const unica = !args.sinFallback ? sucursalUnica.get(c.empresa_id) : undefined;
    if (unica) {
      plan.push({
        id: c.id,
        sucursalId: unica.id,
        via: 'SUCURSAL ÚNICA',
        detalle: `${etiqueta} → única sucursal activa "${unica.descripcion}"`,
      });
      continue;
    }

    sinResolver.push(
      `${etiqueta} | sin depósito${args.sinFallback ? '' : ' y la empresa tiene más de una sucursal'}`,
    );
  }

  const porVia = new Map<string, Plan[]>();
  for (const p of plan) {
    const arr = porVia.get(p.via) ?? [];
    arr.push(p);
    porVia.set(p.via, arr);
  }
  for (const [via, items] of porVia) {
    console.log(`${via}: ${items.length}`);
    items.slice(0, 10).forEach((i) => console.log(`   · ${i.detalle}`));
    if (items.length > 10) console.log(`   … y ${items.length - 10} más`);
    console.log();
  }

  if (sinResolver.length > 0) {
    console.log(`SIN RESOLVER (quedan como están): ${sinResolver.length}`);
    sinResolver.slice(0, 15).forEach((d) => console.log(`   · ${d}`));
    if (sinResolver.length > 15) console.log(`   … y ${sinResolver.length - 15} más`);
    console.log();
  }

  if (!args.apply) {
    console.log('DRY-RUN — no se escribieron cambios. Corré con --apply para aplicar.\n');
    await prisma.$disconnect();
    return;
  }

  // Se agrupa por sucursal para hacer un updateMany por destino y no uno por
  // fila. La condición `sucursal_id: null` se repite en el update para no pisar
  // una compra que haya recibido sucursal entre la lectura y la escritura.
  const porSucursal = new Map<string, string[]>();
  for (const p of plan) {
    const arr = porSucursal.get(p.sucursalId) ?? [];
    arr.push(p.id);
    porSucursal.set(p.sucursalId, arr);
  }

  let total = 0;
  for (const [sucursalId, ids] of porSucursal) {
    const r = await prisma.compra_cab.updateMany({
      where: { id: { in: ids }, sucursal_id: null },
      data: { sucursal_id: sucursalId },
    });
    total += r.count;
  }

  console.log(`APLICADO ✅ — ${total} compra(s) con sucursal asignada.\n`);
  await prisma.$disconnect();
}

main()
  .then(() => process.exit(0))
  .catch(async (e) => {
    console.error('Falló el backfill:', e);
    await prisma.$disconnect();
    process.exit(1);
  });
