import { useMemo, useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { supabase } from '../lib/supabase';
import { parsearOpciones } from '../lib/opciones';

// SIMULADOR DE COMBINACION: el costo de UN plato armado, no el promedio.
// El dueno escoge lo mismo que escoge su cliente (2 proteinas, 3 contornos,
// un extra) y ve al momento cuanto cobra, cuanto le cuesta y cuanto le queda.
// Es la respuesta a "cuanta plata se me esta escapando".

export type OpcionCfg = { nombre: string; precio_extra: number };
export type GrupoCfg = { nombre: string; tipo: string; max: number | null; opciones: OpcionCfg[] };
export type CostoDe = { costo: number; sinPrecio: number };
export type RecetaDe = { base: CostoDe; opciones: Map<string, CostoDe> };

const usd = (n: number) => `$${Number(n).toFixed(2)}`;
const VACIO: CostoDe = { costo: 0, sinPrecio: 0 };

// Mismo criterio de semaforo que la tabla de platos, para no confundir al dueno.
function color(margenPct: number | null): string {
  if (margenPct == null) return '#8A8FAF';
  if (margenPct >= 60) return '#22C55E';
  if (margenPct >= 40) return '#FBBF24';
  return '#EF4444';
}

function etiqueta(margenPct: number | null): string {
  if (margenPct == null) return 'Sin precio de venta';
  if (margenPct >= 60) return 'Sano';
  if (margenPct >= 40) return 'Apretado';
  return 'Pierdes plata';
}

// Cuantos renglones caben en un grupo: los "single" son uno solo; los "multi"
// sin tope (los extras) se manejan como lista que crece.
function cupos(g: GrupoCfg): number | null {
  if (g.tipo === 'single') return 1;
  return g.max && g.max > 0 ? g.max : null;
}

// Tablero en blanco: una casilla por cupo, lista vacia en los grupos sin tope.
function vacio(grupos: GrupoCfg[]): Record<string, string[]> {
  const r: Record<string, string[]> = {};
  for (const g of grupos) {
    const cupo = cupos(g);
    r[g.nombre] = cupo ? new Array<string>(cupo).fill('') : [];
  }
  return r;
}

export default function SimuladorCombinacion({
  producto,
  grupos,
  receta,
  marca,
  txtMarca,
  onCerrar,
}: {
  producto: { producto_id: string; nombre: string; precio_usd: number };
  grupos: GrupoCfg[];
  receta: RecetaDe;
  marca: string;
  txtMarca: string;
  onCerrar: () => void;
}) {
  // Elegidas por grupo: los de cupo fijo guardan una casilla por cupo ('' = sin
  // elegir); los de cupo libre guardan la lista de lo agregado.
  const [elegidas, setElegidas] = useState<Record<string, string[]>>(() => vacio(grupos));

  // La combinacion que MAS se pide, sacada de los pedidos reales del plato.
  const masPedidaQ = useQuery({
    queryKey: ['combinacion-mas-pedida', producto.producto_id],
    queryFn: async () => {
      const { data, error } = await supabase
        .from('pedido_items')
        .select('nota, pedidos!inner(recibido_en)')
        .eq('producto_id', producto.producto_id)
        .not('nota', 'is', null)
        .order('recibido_en', { referencedTable: 'pedidos', ascending: false })
        .limit(300);
      if (error) throw error;
      const validas = new Set(grupos.flatMap((g) => g.opciones.map((o) => o.nombre)));
      const cuenta = new Map<string, { lista: string[]; veces: number }>();
      for (const it of data ?? []) {
        const { grupos: gr } = parsearOpciones(it.nota as string | null);
        const lista = gr
          .flatMap((x) => x.val.split(','))
          .map((s) => s.trim())
          .filter((s) => validas.has(s));
        if (!lista.length) continue;
        const clave = [...lista].sort().join('|');
        const y = cuenta.get(clave);
        if (y) y.veces += 1;
        else cuenta.set(clave, { lista, veces: 1 });
      }
      let mejor: { lista: string[]; veces: number } | null = null;
      for (const v of cuenta.values()) if (!mejor || v.veces > mejor.veces) mejor = v;
      return mejor;
    },
  });

  function costoDe(op: string): CostoDe {
    return receta.opciones.get(op) ?? VACIO;
  }

  function precioDe(op: string): number {
    for (const g of grupos) {
      const o = g.opciones.find((x) => x.nombre === op);
      if (o) return Number(o.precio_extra) || 0;
    }
    return 0;
  }

  const planas = useMemo(
    () => Object.values(elegidas).flat().filter(Boolean),
    [elegidas],
  );

  const cuenta = useMemo(() => {
    let costo = receta.base.costo;
    let sinPrecio = receta.base.sinPrecio;
    let sinReceta = 0;
    let extra = 0;
    for (const op of planas) {
      const c = receta.opciones.get(op);
      if (!c) sinReceta += 1;
      costo += c?.costo ?? 0;
      sinPrecio += c?.sinPrecio ?? 0;
      extra += precioDe(op);
    }
    const precio = Number(producto.precio_usd) + extra;
    const gana = precio - costo;
    const pct = precio > 0 ? (gana / precio) * 100 : null;
    return { costo, precio, gana, pct, sinPrecio, sinReceta };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [planas, receta, producto.precio_usd]);

  // Peor y mejor caso del plato. Se mide por lo que DEJA cada opcion (lo que
  // cobra menos lo que cuesta), no por lo que cuesta: una opcion cara que se
  // cobra aparte puede dejar mas que una barata incluida. Solo entran las que
  // tienen receta; las que no, no se sabe cuanto cuestan y ensuciarian el caso.
  function llenar(peor: boolean) {
    const nuevo: Record<string, string[]> = {};
    for (const g of grupos) {
      const cupo = cupos(g);
      if (!cupo) {
        nuevo[g.nombre] = [];
        continue;
      }
      const deja = (o: OpcionCfg) => (Number(o.precio_extra) || 0) - costoDe(o.nombre).costo;
      const ordenadas = g.opciones
        .filter((o) => receta.opciones.has(o.nombre))
        .sort((a, b) => (peor ? deja(a) - deja(b) : deja(b) - deja(a)));
      nuevo[g.nombre] = new Array<string>(cupo).fill('').map((_, i) => ordenadas[i]?.nombre ?? '');
    }
    setElegidas(nuevo);
  }

  function ponerLista(lista: string[]) {
    const nuevo: Record<string, string[]> = {};
    for (const g of grupos) {
      const cupo = cupos(g);
      const mias = lista.filter((op) => g.opciones.some((o) => o.nombre === op));
      nuevo[g.nombre] = cupo ? new Array(cupo).fill('').map((_, i) => mias[i] ?? '') : mias;
    }
    setElegidas(nuevo);
  }

  function limpiar() {
    setElegidas(vacio(grupos));
  }

  const masPedida = masPedidaQ.data;

  return (
    <>
      <div className="fixed inset-0 z-[1500] bg-black/60" onClick={onCerrar} />
      {/* Alto pegado al contenido (no estirado): en escritorio el plato con pocas
          opciones se veia con medio modal vacio. */}
      <div
        className="fixed inset-x-3 top-1/2 z-[1600] mx-auto flex max-h-[90vh] max-w-lg -translate-y-1/2 flex-col overflow-hidden rounded-2xl ring-1 ring-white/15"
        style={{ background: '#12142B' }}
      >
        <div className="flex items-center justify-between px-4 py-3" style={{ background: marca, color: txtMarca }}>
          <p className="min-w-0 truncate font-extrabold">Simulador · {producto.nombre}</p>
          <button onClick={onCerrar} title="Cerrar" className="rounded-lg px-2 text-xl font-bold leading-none hover:bg-black/10">
            ✕
          </button>
        </div>

        <div className="flex-1 space-y-3 overflow-y-auto p-4">
          <p className="text-xs text-niebla">
            Arma el plato como lo pide tu cliente y mira cuánto te queda de esa combinación exacta.
          </p>

          <div className="flex flex-wrap gap-2">
            {masPedida && (
              <button
                onClick={() => ponerLista(masPedida.lista)}
                className="rounded-lg px-3 py-1.5 text-xs font-bold ring-1 ring-white/15 hover:bg-white/5"
              >
                ⭐ La más pedida ({masPedida.veces})
              </button>
            )}
            <button onClick={() => llenar(true)} className="rounded-lg px-3 py-1.5 text-xs font-bold ring-1 ring-white/15 hover:bg-white/5">
              La que menos te deja
            </button>
            <button onClick={() => llenar(false)} className="rounded-lg px-3 py-1.5 text-xs font-bold ring-1 ring-white/15 hover:bg-white/5">
              La que más te deja
            </button>
            <button onClick={limpiar} className="rounded-lg px-3 py-1.5 text-xs font-bold ring-1 ring-white/15 hover:bg-white/5">
              Limpiar
            </button>
          </div>

          {grupos.map((g) => {
            const cupo = cupos(g);
            const valores = elegidas[g.nombre] ?? [];
            return (
              <div key={g.nombre} className="rounded-2xl bg-superficie p-3 ring-1 ring-white/10">
                <p className="mb-2 text-xs font-bold uppercase tracking-wide text-niebla">{g.nombre}</p>

                {cupo ? (
                  <div className="space-y-2">
                    {new Array(cupo).fill(0).map((_, i) => (
                      <select
                        key={i}
                        value={valores[i] ?? ''}
                        onChange={(e) => {
                          const copia = [...valores];
                          copia[i] = e.target.value;
                          setElegidas({ ...elegidas, [g.nombre]: copia });
                        }}
                        className="w-full rounded-xl bg-black/30 px-3 py-2 text-sm ring-1 ring-white/20"
                      >
                        <option value="">Sin elegir</option>
                        {g.opciones.map((o) => (
                          <option key={o.nombre} value={o.nombre}>
                            {o.nombre}
                            {Number(o.precio_extra) > 0 ? ` (+${usd(o.precio_extra)})` : ''}
                            {receta.opciones.has(o.nombre) ? '' : ' · sin receta'}
                          </option>
                        ))}
                      </select>
                    ))}
                  </div>
                ) : (
                  <div className="space-y-2">
                    <select
                      value=""
                      onChange={(e) => {
                        const v = e.target.value;
                        if (!v || valores.includes(v)) return;
                        setElegidas({ ...elegidas, [g.nombre]: [...valores, v] });
                      }}
                      className="w-full rounded-xl bg-black/30 px-3 py-2 text-sm ring-1 ring-white/20"
                    >
                      <option value="">Agregar...</option>
                      {g.opciones
                        .filter((o) => !valores.includes(o.nombre))
                        .map((o) => (
                          <option key={o.nombre} value={o.nombre}>
                            {o.nombre}
                            {Number(o.precio_extra) > 0 ? ` (+${usd(o.precio_extra)})` : ''}
                            {receta.opciones.has(o.nombre) ? '' : ' · sin receta'}
                          </option>
                        ))}
                    </select>
                    {valores.length > 0 && (
                      <div className="flex flex-wrap gap-1.5">
                        {valores.map((v) => (
                          <button
                            key={v}
                            onClick={() => setElegidas({ ...elegidas, [g.nombre]: valores.filter((x) => x !== v) })}
                            className="rounded-full bg-black/30 px-3 py-1 text-xs ring-1 ring-white/15"
                          >
                            {v} ✕
                          </button>
                        ))}
                      </div>
                    )}
                  </div>
                )}
              </div>
            );
          })}

          {planas.length > 0 && (
            <div className="rounded-2xl bg-superficie p-3 text-xs ring-1 ring-white/10">
              <p className="mb-1 font-bold">Lo que lleva este plato</p>
              <ul className="space-y-0.5 text-niebla">
                <li className="flex justify-between">
                  <span>Base del plato</span>
                  <span>{usd(receta.base.costo)}</span>
                </li>
                {planas.map((op) => (
                  <li key={op} className="flex justify-between">
                    <span className="truncate pr-2">
                      {op}
                      {precioDe(op) > 0 ? ` (cobras +${usd(precioDe(op))})` : ''}
                    </span>
                    <span>{receta.opciones.has(op) ? usd(costoDe(op).costo) : 'sin receta'}</span>
                  </li>
                ))}
              </ul>
            </div>
          )}

          {(cuenta.sinPrecio > 0 || cuenta.sinReceta > 0) && (
            <div className="rounded-2xl bg-amber-500/10 p-3 text-xs font-semibold text-amber-300 ring-1 ring-amber-500/30">
              {cuenta.sinPrecio > 0 && (
                <p>
                  Ojo: {cuenta.sinPrecio} ingrediente{cuenta.sinPrecio === 1 ? '' : 's'} de esta combinación no tiene
                  precio cargado. El costo de abajo está incompleto hasta que subas la factura o pongas el precio a mano.
                </p>
              )}
              {cuenta.sinReceta > 0 && (
                <p className="mt-1">
                  {cuenta.sinReceta} de las que elegiste no tiene receta todavía, así que cuenta como cero.
                </p>
              )}
            </div>
          )}
        </div>

        <div className="border-t border-white/10 p-4">
          <div className="grid grid-cols-3 gap-2 text-center">
            <div className="rounded-xl bg-superficie p-2 ring-1 ring-white/10">
              <p className="text-lg font-extrabold">{usd(cuenta.precio)}</p>
              <p className="text-[11px] text-niebla">Cobras</p>
            </div>
            <div className="rounded-xl bg-superficie p-2 ring-1 ring-white/10">
              <p className="text-lg font-extrabold">{usd(cuenta.costo)}</p>
              <p className="text-[11px] text-niebla">Te cuesta</p>
            </div>
            <div className="rounded-xl bg-superficie p-2 ring-1 ring-white/10">
              <p className="text-lg font-extrabold" style={{ color: color(cuenta.pct) }}>
                {usd(cuenta.gana)}
              </p>
              <p className="text-[11px] text-niebla">Te queda</p>
            </div>
          </div>
          <p className="mt-2 text-center text-xs font-semibold" style={{ color: color(cuenta.pct) }}>
            {cuenta.pct != null ? `${cuenta.pct.toFixed(0)}% de margen · ${etiqueta(cuenta.pct)}` : etiqueta(null)}
          </p>
        </div>
      </div>
    </>
  );
}
