/**
 * "Pendiente" = el dato todavía no está cargado.
 *
 * Para montos, 0 cuenta como pendiente: en un catálogo migrado, costo 0 significa
 * "nunca se cargó", no "es gratis". Para referenciales solo cuenta null, porque no
 * hay un valor equivalente a vacío.
 *
 * Esto es lo que permite responder "¿dónde me quedé?" sin guardar posición: el
 * conjunto pendiente se recalcula de la base y se achica solo a medida que el
 * usuario carga datos.
 */

export type CampoPendiente = 'costo' | 'precio' | 'categoria' | 'marca';

export const ES_PENDIENTE: CampoPendiente[] = ['costo', 'precio', 'categoria', 'marca'];

export function wherePendiente(campo: CampoPendiente | undefined): Record<string, unknown> {
  switch (campo) {
    case 'costo':
      return { OR: [{ precio_costo: null }, { precio_costo: 0 }] };
    case 'precio':
      return { OR: [{ precio: null }, { precio: 0 }] };
    case 'categoria':
      return { categoria_id: null };
    case 'marca':
      return { marca_id: null };
    default:
      return {};
  }
}

/**
 * Agrega el filtro de pendientes a un `where` de Prisma SIN pisar lo que ya tenga.
 *
 * Importa: `findAll` ya usa `whereClause.OR` para la búsqueda por texto
 * (`productos.service.ts:840`), y el fragmento de costo/precio también es un `OR`.
 * Spreadear uno sobre otro haría que el segundo pise al primero y la búsqueda
 * dejara de filtrar, en silencio. Componer bajo `AND` conserva ambos: Prisma
 * combina `OR` y `AND` del mismo nivel con Y lógico.
 */
export function componerPendiente(
  where: Record<string, any>,
  campo: CampoPendiente | undefined,
): void {
  const fragmento = wherePendiente(campo);
  if (Object.keys(fragmento).length === 0) return;
  where.AND = [...(where.AND ?? []), fragmento];
}

/**
 * Valor especial en los filtros `categoria_id` / `marca_id` (lista separada por
 * comas) que significa "sin asignar". Convive con ids reales: "sin,<uuid>"
 * trae los productos sin categoría MÁS los de esa categoría.
 */
export const SIN_ASIGNAR = 'sin';

/**
 * Aplica un filtro de referencial (categoría o marca) a un `where` de Prisma.
 *
 * Sin esto, el valor "sin" llegaba a Postgres dentro de un `IN (...)` de uuids y
 * rompía la consulta; y no había forma de listar los productos sin categoría.
 * "Sin asignar" es `null`, el mismo criterio que usa `wherePendiente`, así el
 * listado y el contador de la edición masiva cuentan lo mismo.
 *
 * Se compone bajo `AND` por lo mismo que `componerPendiente`: el `OR` de
 * "sin + ids" no debe pisar el `OR` de la búsqueda por texto.
 */
export function componerFiltroReferencial(
  where: Record<string, any>,
  columna: 'categoria_id' | 'marca_id',
  lista: string | undefined,
): void {
  if (!lista) return;
  const valores = lista.split(',').map((s) => s.trim()).filter(Boolean);
  if (valores.length === 0) return;

  const incluyeSin = valores.includes(SIN_ASIGNAR);
  const ids = valores.filter((v) => v !== SIN_ASIGNAR);

  const conId = ids.length === 1 ? { [columna]: ids[0] } : { [columna]: { in: ids } };
  let fragmento: Record<string, unknown>;
  if (incluyeSin && ids.length > 0) fragmento = { OR: [{ [columna]: null }, conId] };
  else if (incluyeSin) fragmento = { [columna]: null };
  else fragmento = conId;

  where.AND = [...(where.AND ?? []), fragmento];
}
