/**
 * De dónde salió un movimiento de tesorería y dónde se anula.
 *
 * Un movimiento generado por otro documento (un cheque, un gasto, un recibo) no
 * se anula desde Tesorería: hay que anular el documento, que revierte el saldo
 * y su propio estado juntos. La pantalla necesita decir eso con nombre y
 * número, no solo deshabilitar el botón.
 */

export interface MetaOrigen {
  etiqueta: string;
  /** Dónde lo anula el usuario, con las palabras que ve en el menú. */
  pantalla: string;
  /** Ruta del ERP para llevarlo ahí; null si no hay una pantalla directa. */
  ruta: string | null;
}

export interface DatosDocumento {
  numero: string | null;
  fecha: Date | null;
  estado: string | null;
  anulado: boolean;
}

export interface OrigenMovimiento extends MetaOrigen, Partial<DatosDocumento> {
  tipo: string;
  /**
   * El documento ya está anulado pero su movimiento sigue vivo: anular acá es
   * lo único que queda para cerrar el caso.
   */
  permiteAnularDirecto: boolean;
}

export const ORIGENES_MOVIMIENTO: Record<string, MetaOrigen> = {
  CHEQUE_DEPOSITADO: { etiqueta: 'Cheque depositado', pantalla: 'Tesorería → Cheques', ruta: '/tesoreria?tab=cheques' },
  CHEQUE_DEBITADO: { etiqueta: 'Cheque debitado', pantalla: 'Tesorería → Cheques', ruta: '/tesoreria?tab=cheques' },
  CHEQUE_RECHAZADO: { etiqueta: 'Reversa de cheque', pantalla: 'Tesorería → Cheques', ruta: '/tesoreria?tab=cheques' },
  CHEQUE_ANULADO: { etiqueta: 'Reversa de cheque', pantalla: 'Tesorería → Cheques', ruta: '/tesoreria?tab=cheques' },
  TRANSFERENCIA_ORIGEN: { etiqueta: 'Transferencia entre cuentas', pantalla: 'Tesorería → Transferencias', ruta: '/tesoreria?tab=transferencias' },
  TRANSFERENCIA_DESTINO: { etiqueta: 'Transferencia entre cuentas', pantalla: 'Tesorería → Transferencias', ruta: '/tesoreria?tab=transferencias' },
  ORDEN_PAGO_PROVEEDOR: { etiqueta: 'Orden de pago a proveedor', pantalla: 'Compras → Órdenes de pago', ruta: '/compras?tab=ordenes-pago' },
  gasto_cab: { etiqueta: 'Gasto', pantalla: 'Compras → Gastos', ruta: '/compras?tab=gastos' },
  recibos_multi: { etiqueta: 'Recibo de cobro', pantalla: 'Cobranzas → Recibos', ruta: '/cobranzas/recibos' },
  recibos_cobro: { etiqueta: 'Recibo de cobro', pantalla: 'Cobranzas → Recibos', ruta: '/cobranzas/recibos' },
  RENDICION_ADELANTO: { etiqueta: 'Adelanto de viáticos', pantalla: 'RRHH → Rendición de viáticos', ruta: '/rrhh?tab=viaticos' },
  RENDICION_DEVOLUCION: { etiqueta: 'Reintegro de viáticos', pantalla: 'RRHH → Rendición de viáticos', ruta: '/rrhh?tab=viaticos' },
  rrhh_acreditacion: { etiqueta: 'Acreditación de sueldos', pantalla: 'RRHH → Acreditaciones', ruta: '/rrhh' },
  rrhh_desvinculacion: { etiqueta: 'Liquidación de desvinculación', pantalla: 'RRHH → Desvinculaciones', ruta: '/rrhh' },
  rrhh_reporte_ips: { etiqueta: 'Pago de IPS', pantalla: 'RRHH → Reportes IPS', ruta: '/rrhh' },
  IMPORT_EXTRACTO: { etiqueta: 'Importación de extracto', pantalla: 'Tesorería → Conciliación', ruta: '/tesoreria?tab=conciliacion' },
  CONCILIACION_AJUSTE: { etiqueta: 'Ajuste de conciliación', pantalla: 'Tesorería → Conciliación', ruta: '/tesoreria?tab=conciliacion' },
};

const GENERICO: MetaOrigen = {
  etiqueta: 'Documento vinculado',
  pantalla: 'la pantalla del documento que lo generó',
  ruta: null,
};

export function describirOrigen(
  origenTipo: string | null | undefined,
  datos: DatosDocumento | null,
): OrigenMovimiento | null {
  if (!origenTipo) return null;
  const meta = ORIGENES_MOVIMIENTO[origenTipo] ?? GENERICO;
  return {
    tipo: origenTipo,
    ...meta,
    numero: datos?.numero ?? null,
    fecha: datos?.fecha ?? null,
    estado: datos?.estado ?? null,
    anulado: datos?.anulado ?? false,
    permiteAnularDirecto: Boolean(datos?.anulado),
  };
}

/**
 * Resuelve el documento de cada movimiento. `buscar` recibe el tipo y todos los
 * ids de ese tipo: una consulta por tipo, no una por movimiento.
 */
export async function resolverOrigenes(
  movimientos: Array<{ id: string; origen_tipo?: string | null; origen_id?: string | null }>,
  buscar: (tipo: string, ids: string[]) => Promise<Map<string, DatosDocumento>>,
): Promise<Map<string, OrigenMovimiento>> {
  const porTipo = new Map<string, Set<string>>();
  for (const mov of movimientos) {
    if (!mov.origen_tipo || !mov.origen_id) continue;
    const ids = porTipo.get(mov.origen_tipo) ?? new Set<string>();
    ids.add(mov.origen_id);
    porTipo.set(mov.origen_tipo, ids);
  }

  const datosPorTipo = new Map<string, Map<string, DatosDocumento>>();
  for (const [tipo, ids] of porTipo) {
    try {
      datosPorTipo.set(tipo, await buscar(tipo, [...ids]));
    } catch {
      // Si no se puede leer el documento, igual se explica de dónde vino.
      datosPorTipo.set(tipo, new Map());
    }
  }

  const salida = new Map<string, OrigenMovimiento>();
  for (const mov of movimientos) {
    if (!mov.origen_tipo) continue;
    const datos = mov.origen_id ? (datosPorTipo.get(mov.origen_tipo)?.get(mov.origen_id) ?? null) : null;
    const origen = describirOrigen(mov.origen_tipo, datos);
    if (origen) salida.set(mov.id, origen);
  }
  return salida;
}
