// Form sections — receive `s` (state) and `set` updater functions
const { useRef, useEffect } = React;

// "admin" (default) ve precios y guarda directo; "cliente" (formulario
// público /customer/cotizador) arma la misma configuración de pastel pero
// sin ver ningún precio — solo envía la solicitud para que el vendedor cotice.
const MODE = (typeof window !== "undefined" && window.COTIZADOR_MODE) || "admin";
const IS_CLIENT = MODE === "cliente";

const Field = ({ label, children, hint, full }) => (
  <label className={"field " + (full ? "full" : "")}>
    <span className="field-label">{label}</span>
    {children}
    {hint && <span className="field-hint">{hint}</span>}
  </label>
);

const Input = (props) => <input {...props} className={"input " + (props.className || "")} />;
const TextArea = (props) => <textarea {...props} className={"input textarea " + (props.className || "")} />;

// Solo dígitos + separadores típicos de teléfono (espacio, guión, paréntesis,
// +) — para que no se cuele texto en un campo que en realidad se usa para
// marcar o para buscar por número (LeadModel/ClienteModel resuelven clientes
// por teléfono, así que un teléfono con letras rompe esa búsqueda).
const soloTelefono = (v) => (v || "").replace(/[^0-9+()\-\s]/g, "").slice(0, 20);

// Clamp genérico para inputs numéricos — evita negativos y, si se da `max`,
// evita que se pase de un tope (ej. el anticipo no puede superar el total).
const clampNum = (v, min, max) => {
  if (v === "" || v === null || v === undefined) return "";
  let n = Number(v);
  if (Number.isNaN(n)) return "";
  if (min !== undefined) n = Math.max(min, n);
  if (max !== undefined) n = Math.min(max, n);
  return n;
};
const Select = ({ options, ...props }) => (
  <select {...props} className={"input select " + (props.className || "")}>
    {options.map(o => <option key={o.value ?? o} value={o.value ?? o}>{o.label ?? o.name ?? o}</option>)}
  </select>
);

function Toggle({ checked, onChange, label }) {
  return (
    <label className="toggle">
      <input type="checkbox" checked={!!checked} onChange={e => onChange(e.target.checked)} />
      <span className="toggle-track"><span className="toggle-thumb" /></span>
      <span className="toggle-label">{label}</span>
    </label>
  );
}

function Chips({ value, onChange, options, allowEmpty }) {
  return (
    <div className="chips">
      {options.map(o => {
        const active = value === o.id;
        return (
          <button
            key={o.id}
            type="button"
            className={"chip " + (active ? "active" : "")}
            onClick={() => onChange(active && allowEmpty ? "" : o.id)}
          >
            {o.color && <i className="chip-dot" style={{ background: o.color }} />}
            <span>{o.name}</span>
            {o.extra && <span className="chip-extra">+</span>}
          </button>
        );
      })}
    </div>
  );
}

// ========== Wizard ==========
// El formulario completo era una sola columna larguísima: el cliente tenía que
// hacer scroll por seis tarjetas antes de poder enviar. Se parte en pasos, con
// el mismo patrón visual del wizard de Rizz (bolita numerada + título + guía).
const WIZARD_STEPS = [
  { id: 1, label: "Cliente",    hint: "Datos de contacto" },
  { id: 2, label: "Entrega",    hint: "Fecha y ubicación" },
  { id: 3, label: "Pastel",     hint: "Pisos y sabores" },
  { id: 4, label: "Decoración", hint: "Extras y figuras" },
  { id: 5, label: "Resumen",    hint: IS_CLIENT ? "Enviar solicitud" : "Guardar cotización" },
];

// Qué falta para poder avanzar. Se valida al intentar pasar de paso y no al
// escribir, para no llenar de rojo un formulario que apenas se está llenando.
function validarPaso(paso, s) {
  const faltan = [];

  if (paso === 1) {
    if (!(s.client.name || "").trim())  faltan.push("el nombre del solicitante");
    if (!(s.client.phone || "").trim()) faltan.push("el teléfono de contacto");
  }

  if (paso === 2) {
    if (!s.delivery.date) faltan.push("la fecha de entrega");
    if (!(s.delivery.address || "").trim()) faltan.push("la dirección de entrega");
    // Sin pin no hay km, y sin km el envío se cobraría en $0.
    if (!s.delivery.lat || !s.delivery.lng) faltan.push("ubicar el punto en el mapa");
  }

  if (paso === 3) {
    if (!(Number(s.cake.people) > 0)) faltan.push("el número de personas");
  }

  return faltan;
}

function WizardNav({ current, maxAlcanzado, onGo }) {
  return (
    <ol className="wizard-nav">
      {WIZARD_STEPS.map(st => {
        const hecho     = st.id < maxAlcanzado;
        const activo    = st.id === current;
        const navegable = st.id <= maxAlcanzado;
        return (
          <li key={st.id}
              className={[
                "wizard-step",
                activo ? "active" : "",
                hecho ? "done" : "",
                navegable ? "nav" : "",
              ].join(" ").trim()}
              onClick={() => navegable && onGo(st.id)}>
            <span className="wizard-bullet">{hecho && !activo ? "✓" : st.id}</span>
            <span className="wizard-text">
              <strong>{st.label}</strong>
              <em>{st.hint}</em>
            </span>
          </li>
        );
      })}
    </ol>
  );
}

function WizardFooter({ current, onPrev, onNext, errores }) {
  const esUltimo = current === WIZARD_STEPS.length;
  return (
    <div className="wizard-footer">
      {errores.length > 0 && (
        <div className="wizard-errors">
          Para continuar falta {errores.join(", ").replace(/,([^,]*)$/, " y$1")}.
        </div>
      )}
      <div className="wizard-actions">
        <button type="button" className="btn ghost" disabled={current === 1} onClick={onPrev}>
          ← Atrás
        </button>
        <span className="wizard-count">Paso {current} de {WIZARD_STEPS.length}</span>
        {!esUltimo && (
          <button type="button" className="btn primary" onClick={onNext}>
            Continuar →
          </button>
        )}
      </div>
    </div>
  );
}

// Selector de color libre (Huebee, ya incluido en el tema Rizz). Complementa
// a la paleta con nombre: cuando el cliente trae un color que no está en la
// lista, aquí se elige el tono exacto y se guarda el HEX.
function ColorPickerHuebee({ value, onChange }) {
  const inputRef = useRef(null);
  const hueRef   = useRef(null);
  // La instancia de Huebee se crea una sola vez, pero `onChange` cambia en
  // cada render (depende del piso): si se capturara en el closure inicial,
  // los cambios se escribirían siempre en el primer piso.
  const cbRef = useRef(onChange);
  cbRef.current = onChange;

  useEffect(() => {
    if (!inputRef.current || typeof Huebee === "undefined") return;

    const hb = new Huebee(inputRef.current, {
      notation: "hex",
      saturations: 3,
      shades: 6,
      hues: 12,
      setText: false,     // el input lo controla React, no Huebee
      setBGColor: false,
    });
    hb.on("change", (color) => { if (cbRef.current) cbRef.current(color); });
    hueRef.current = hb;

    return () => { if (hueRef.current && hueRef.current.destroy) hueRef.current.destroy(); };
  }, []);

  if (typeof Huebee === "undefined") return null;

  return (
    <div className="color-custom">
      <span className="color-custom-chip" style={{ background: value || "#ffffff" }} />
      <input ref={inputRef} className="input color-custom-input" readOnly
             value={(value || "").toUpperCase()} placeholder="Elegir otro color" />
    </div>
  );
}

function SectionCard({ title, num, children, action }) {
  return (
    <section className="section-card">
      <header className="section-head">
        {num && <span className="section-num">{num}</span>}
        <h2>{title}</h2>
        {action && <div className="section-action">{action}</div>}
      </header>
      <div className="section-body">{children}</div>
    </section>
  );
}

// ========== Cliente ==========
function ClienteForm({ s, set, onSave, onClear }) {
  return (
    <SectionCard title="Datos del cliente" num="01" action={
      <div className="cluster">
        {/* "Guardar por folio" es un atajo local (localStorage) del propio
            equipo del vendedor — no aplica en el cotizador público: el
            visitante no tiene sesión ni folios previos en ese navegador. */}
        {!IS_CLIENT && <button className="btn ghost" onClick={onSave} type="button">Guardar por folio</button>}
        <button className="btn ghost danger" onClick={onClear} type="button">Limpiar</button>
      </div>
    }>
      <div className="grid-2">
        <Field label="Código de cliente">
          <Input value={s.client.code} onChange={e => set("client.code", e.target.value)} placeholder="EKA, YURICA..." />
        </Field>
        <Field label="Nombre del solicitante">
          <Input value={s.client.name} onChange={e => set("client.name", e.target.value)} placeholder="Nombre completo" />
        </Field>
        <Field label="Teléfono del solicitante">
          <Input type="tel" inputMode="tel" value={s.client.phone} onChange={e => set("client.phone", soloTelefono(e.target.value))} placeholder="222 000 0000" />
        </Field>
        <Field label="Correo (opcional)">
          <Input type="email" value={s.client.email} onChange={e => set("client.email", e.target.value)} placeholder="cliente@correo.com" />
        </Field>
      </div>
    </SectionCard>
  );
}

// Panel "Combinaciones de teclas" de Google.
//
// Se inspeccionó el DOM real (no se reproduce en navegadores sin composición):
// al arrastrar dentro del mapa, Google inyecta el panel como un <div> HERMANO
// del mapa, hijo directo de nuestro contenedor .delivery-map. Lo vuelve a
// crear en cada interacción, así que no basta con quitarlo una vez.
//
// Por eso se observa SOLO la lista de hijos directos del contenedor propio
// (childList sin subtree) y nunca se toca el primer hijo, que es el mapa.
// Un intento anterior recorría el árbol completo ocultando cualquier nodo con
// ese texto y congelaba el mapa: el texto del pie vive dentro de la misma
// rama que la capa interactiva. No volver a hacer eso.
//
// El link del pie sí es un <button>, y ocultar botones sí es seguro (se probó:
// el mapa siguió arrastrándose con normalidad). Se oculta también porque mide
// 112px y queda en los últimos 15px de un mapa de 220px, o sea justo donde
// cae el cursor al soltar el pin.
function quitarPanelDeAtajos(mapEl, raizDelMapa) {
  const ES_ATAJOS = /combinaciones de teclas|keyboard shortcuts/i;

  const barrer = () => {
    // 1) El panel: hermano del mapa, hijo directo del contenedor.
    Array.prototype.slice.call(mapEl.children).forEach(hijo => {
      if (hijo === raizDelMapa) return;                       // jamás el mapa
      if (ES_ATAJOS.test(hijo.textContent || "")) hijo.remove();
    });
    // 2) El link del pie que lo abre (solo <button>, nunca contenedores).
    mapEl.querySelectorAll("button").forEach(b => {
      if (ES_ATAJOS.test(b.textContent || "")) b.style.display = "none";
    });
  };

  barrer();
  const observador = new MutationObserver(barrer);
  observador.observe(mapEl, { childList: true });
  return { observador, barrer };
}

// ========== Mapa de entrega ==========
// Misma lógica que ya usa mariasdechocolate.com/customer/carrito: un
// marcador fijo en la tienda, un pin arrastrable en el destino, autocomplete
// de direcciones sobre el input, y el km real sale de DistanceMatrixService
// — nunca de una distancia tecleada a ojo. Corre en jQuery allá; aquí es un
// componente React que hace lo mismo con la Maps JavaScript API directa.
function DeliveryMap({ addressInputRef, lat, lng, onResolve }) {
  const mapElRef  = useRef(null);
  const readyRef  = useRef(false);
  const mapRef    = useRef(null);
  const markerRef = useRef(null);
  const limpiezaRef = useRef(null);
  const [mapError, setMapError] = React.useState(false);

  useEffect(() => {
    if (readyRef.current || !mapElRef.current) return;
    if (typeof google === "undefined" || !google.maps) {
      setMapError(true);
      return;
    }
    readyRef.current = true;

    try {
      const store = D.storeLocation;
      const start = (lat && lng) ? { lat: Number(lat), lng: Number(lng) } : store;
      const distanceService = new google.maps.DistanceMatrixService();

      // Opciones EXACTAMENTE como en mariasdechocolate.com (jquery.common.g-map-init.js):
      // solo center y zoom. Pasar keyboardShortcuts:false y streetViewControl:false
      // era justo lo que hacía aparecer el panel "Combinaciones de teclas" al mover
      // el pin — el mapa de Marías, sin esas opciones, nunca lo muestra.
      // No agregar más opciones aquí sin probarlo contra ese comportamiento.
      const map = new google.maps.Map(mapElRef.current, {
        center: start,
        zoom: 15,
      });

      // El mapa queda como primer hijo del contenedor; se guarda para que el
      // limpiador del panel de atajos sepa qué nodo NO debe tocar nunca.
      const raizDelMapa = mapElRef.current.firstElementChild;
      const atajos = quitarPanelDeAtajos(mapElRef.current, raizDelMapa);
      limpiezaRef.current = atajos.observador;
      // Google repinta sus controles al terminar cada interacción: ahí vuelve
      // a aparecer el link del pie, así que se rebarre en cada 'idle'.
      map.addListener("idle", atajos.barrer);

      new google.maps.Marker({
        position: store,
        map,
        title: D.business?.name || "Deus Cake",
      });

      const marker = new google.maps.Marker({ position: start, map, draggable: true, title: "Destino" });
      mapRef.current    = map;
      markerRef.current = marker;

      const resolveFrom = (loc) => {
        distanceService.getDistanceMatrix({
          origins: [store],
          destinations: [loc],
          travelMode: "DRIVING",
          unitSystem: google.maps.UnitSystem.METRIC,
        }, (response, status) => {
          if (status !== "OK") return;
          const el = response.rows[0]?.elements[0];
          if (!el || el.status !== "OK") return;
          onResolve({ lat: loc.lat, lng: loc.lng, km: Math.round((el.distance.value / 1000) * 10) / 10 });
        });
      };

      marker.addListener("dragend", () => {
        const pos = marker.getPosition();
        resolveFrom({ lat: pos.lat(), lng: pos.lng() });
      });

      if (addressInputRef?.current) {
        const autocomplete = new google.maps.places.Autocomplete(addressInputRef.current, {
          fields: ["geometry", "formatted_address"],
          componentRestrictions: { country: "mx" },
        });
        autocomplete.addListener("place_changed", () => {
          const place = autocomplete.getPlace();
          if (!place.geometry) return;
          const loc = { lat: place.geometry.location.lat(), lng: place.geometry.location.lng() };
          marker.setPosition(loc);
          map.setCenter(loc);
          map.setZoom(16);
          onResolve({ lat: loc.lat, lng: loc.lng, address: place.formatted_address });
          resolveFrom(loc);
        });
      }
    } catch (e) {
      console.warn("[Cotizador] mapa:", e);
      setMapError(true);
    }

    // El wizard desmonta el paso de entrega al avanzar: sin esto se acumularía
    // un observador vivo por cada entrada y salida del paso.
    return () => {
      if (limpiezaRef.current) { limpiezaRef.current.disconnect(); limpiezaRef.current = null; }
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // El estado puede llegar DESPUÉS del montaje: abrir ?cotizacion=ID (ver o
  // editar una cotización guardada), ?solicitud=ID o importar un JSON cargan
  // la entrega por AJAX. Sin esto el mapa se quedaba con el pin en la tienda
  // aunque la cotización sí tuviera su ubicación.
  useEffect(() => {
    if (!mapRef.current || !markerRef.current) return;
    if (!isFinite(Number(lat)) || !isFinite(Number(lng)) || (!Number(lat) && !Number(lng))) return;

    const destino = { lat: Number(lat), lng: Number(lng) };
    const actual  = markerRef.current.getPosition();

    // Si el cambio vino del propio pin (dragend / autocomplete) el marcador ya
    // está ahí — no hace falta reposicionar ni pelear con el zoom del usuario.
    if (actual && Math.abs(actual.lat() - destino.lat) < 1e-7 && Math.abs(actual.lng() - destino.lng) < 1e-7) return;

    markerRef.current.setPosition(destino);
    mapRef.current.setCenter(destino);
    mapRef.current.setZoom(16);
  }, [lat, lng]);

  if (mapError) {
    return <div className="delivery-map delivery-map-error">Mapa no disponible — captura el km manualmente.</div>;
  }
  return <div className="delivery-map" ref={mapElRef} />;
}

// ========== Entrega ==========
function EntregaForm({ s, set, D }) {
  const addressInputRef = useRef(null);

  return (
    <SectionCard title="Datos de entrega" num="02">
      <div className="grid-2">
        <Field label="Fecha de entrega">
          <Input type="date" value={s.delivery.date} onChange={e => set("delivery.date", e.target.value)} />
        </Field>
        <Field label="Hora de entrega">
          <Input type="time" value={s.delivery.time} onChange={e => set("delivery.time", e.target.value)} />
        </Field>
        <Field label="Nombre del salón o casa particular" full>
          <Input value={s.delivery.locationName} onChange={e => set("delivery.locationName", e.target.value)} placeholder="Casa particular / Salón ..." />
        </Field>
        {/* Este es el buscador: al escribir, Google sugiere lugares y al elegir
            uno el pin del mapa se coloca solo y se calcula el envío. Mismo
            comportamiento que el campo "Calle y número" de mariasdechocolate.com. */}
        <Field label="Dirección de entrega" full
               hint="Escribe la calle o el lugar y elige una opción de la lista que aparece abajo.">
          <input
            ref={addressInputRef}
            className="input"
            value={s.delivery.address}
            onChange={e => set("delivery.address", e.target.value)}
            placeholder="Busca tu dirección: calle, número, colonia..."
            autoComplete="off"
          />
        </Field>
        <Field label="¿Local o foráneo?">
          <div className="seg">
            <button type="button" className={!s.delivery.foreign ? "seg-on" : ""} onClick={() => set("delivery.foreign", false)}>Local</button>
            <button type="button" className={s.delivery.foreign ? "seg-on" : ""} onClick={() => set("delivery.foreign", true)}>Foráneo</button>
          </div>
        </Field>
        {/* Costo de envío — mismo campo de solo lectura que mariasdechocolate.com:
            lo llena el mapa (Distance Matrix), no se teclea. El cotizador
            público NO lo muestra: el cliente solo ubica su casa y manda la
            solicitud; el precio se lo confirma después el vendedor. */}
        {!IS_CLIENT && (
          <Field label="Costo de envío"
                 hint={`Base $${D.shippingBase} hasta ${D.shippingBaseKm} km · +$${D.shippingPerKm}/km extra`}>
            <div className="money-field">
              <span className="money-prefix">$</span>
              <input className="input money-input" readOnly tabIndex={-1}
                     value={D.computeShipping(Number(s.delivery.km) || 0).toFixed(2)} />
              <span className="money-suffix">
                {Number(s.delivery.km) > 0 ? `${s.delivery.km} km` : "sin ubicar"}
              </span>
            </div>
          </Field>
        )}
        <Field label="Ubica el punto de entrega en el mapa" full hint="Escribe la dirección arriba (autocompletar) o arrastra el pin — la distancia y el envío se calculan solos.">
          <div className="map-hint">📍 Ingresa la dirección y confirma el pin en el mapa.</div>
          <DeliveryMap
            addressInputRef={addressInputRef}
            lat={s.delivery.lat}
            lng={s.delivery.lng}
            onResolve={({ lat, lng, address, km }) => {
              if (lat != null) set("delivery.lat", lat);
              if (lng != null) set("delivery.lng", lng);
              if (address != null) set("delivery.address", address);
              if (km != null) set("delivery.km", km);
            }}
          />
        </Field>
        <Field label="Nombre de quien recibe">
          <Input value={s.delivery.receiverName} onChange={e => set("delivery.receiverName", e.target.value)} />
        </Field>
        <Field label="Teléfono de quien recibe">
          <Input type="tel" inputMode="tel" value={s.delivery.receiverPhone} onChange={e => set("delivery.receiverPhone", soloTelefono(e.target.value))} />
        </Field>
      </div>
    </SectionCard>
  );
}

// ========== Pastel: configuración general ==========
function CakeGeneralForm({ s, set, D, totals }) {
  return (
    <SectionCard title="Configuración del pastel" num="03">
      <Field label="Número de pisos" hint="De 1 a 7 pisos">
        <div className="pisos-grid">
          {[1,2,3,4,5,6,7].map(n => (
            <button key={n} type="button"
              className={"piso-btn " + (s.cake.tiers.length === n ? "active" : "")}
              onClick={() => set("cake.tiersCount", n)}>
              <strong>{n}</strong>
              <span>piso{n>1?"s":""}</span>
              <em>~{D.servingsByTier[n]} pers.</em>
            </button>
          ))}
        </div>
      </Field>

      <div className="grid-2">
        <Field label="Número de personas (porciones)" hint={IS_CLIENT
          ? `Sugerido: ${D.servingsByTier[s.cake.tiers.length] || "—"}`
          : `Sugerido: ${D.servingsByTier[s.cake.tiers.length] || "—"} · Precio por persona: ${fmt(D.pricePerPerson(s.cake.people))}`}>
          <Input type="number" min="1" value={s.cake.people} onChange={e => set("cake.people", clampNum(e.target.value, 1))} />
        </Field>
        <Field label="Tema del pastel">
          <Input value={s.cake.theme} onChange={e => set("cake.theme", e.target.value)} placeholder="Cumpleaños, boda, baby shower..." />
        </Field>
        <Field label="Tipo de evento" hint="Para darte seguimiento (ej. recordarte el 1er añito después de un bautizo)">
          <Select value={s.tipoEvento || "otro"} onChange={e => set("tipoEvento", e.target.value)}
            options={[
              { value: "bautizo", label: "Bautizo" },
              { value: "primer_anio", label: "1er añito" },
              { value: "cumpleanos", label: "Cumpleaños" },
              { value: "boda", label: "Boda" },
              { value: "otro", label: "Otro" },
            ]} />
        </Field>
        <Field label="Tipo de hidratación" hint="Informativo">
          <Select value={s.cake.hydration} onChange={e => set("cake.hydration", e.target.value)}
            options={[{value:"ALTO", label:"Alto"}, {value:"MEDIO", label:"Medio"}, {value:"BAJO", label:"Bajo"}]} />
        </Field>
        <Field label="Cobertura (Buttercream o Fondant)">
          <Chips value={s.cake.covering} onChange={v => set("cake.covering", v)} options={D.coverings} />
        </Field>
      </div>

      <div className="same-toggle">
        <Toggle checked={s.cake.sameForAll}
          onChange={v => set("cake.sameForAll", v)}
          label="Usar el mismo sabor y relleno para todos los pisos" />
      </div>

      {s.cake.sameForAll && (
        <div className="grid-2">
          <Field label="Sabor del bizcocho (todos los pisos)">
            <Chips value={s.cake.tiers[0]?.flavor} onChange={v => set("cake.baseFlavor", v)} options={D.flavors} />
          </Field>
          <Field label="Relleno (todos los pisos)">
            <Chips value={s.cake.tiers[0]?.filling} onChange={v => set("cake.baseFilling", v)} options={D.fillings} />
          </Field>
        </div>
      )}
    </SectionCard>
  );
}

// ========== Pisos individuales ==========
function TierEditor({ tier, idx, set, D, sameForAll }) {
  const upd = (key, val) => set(`cake.tiers.${idx}.${key}`, val);
  return (
    <div className="tier-editor">
      <div className="tier-editor-head">
        <span className="tier-badge">PISO {idx + 1}{idx === 0 ? " (base)" : ""}</span>
      </div>

      <div className="grid-2">
        <Field label="Tipo de piso">
          <Chips value={tier.tierType} onChange={v => upd("tierType", v)} options={D.tierTypes} />
        </Field>
        <Field label="Acabado de unión">
          <Chips value={tier.union} onChange={v => upd("union", v)} options={D.unionFinish} />
        </Field>
      </div>

      {!sameForAll && (
        <div className="grid-2">
          <Field label="Sabor del bizcocho">
            <Chips value={tier.flavor} onChange={v => upd("flavor", v)} options={D.flavors} />
          </Field>
          <Field label="Relleno">
            <Chips value={tier.filling} onChange={v => upd("filling", v)} options={D.fillings} />
          </Field>
        </div>
      )}

      <Field label="Color del piso"
             hint="Elige de la paleta, o usa 'Elegir otro color' si el cliente trae un tono exacto.">
        <ColorPickerHuebee
          value={tier.colorHex}
          onChange={(hex) => {
            // Si el tono elegido coincide con uno de la paleta se conserva su
            // nombre; si no, el HEX queda como nombre para que cocina y el
            // vendedor vean exactamente lo mismo en la ficha.
            const conocido = D.presetColors.find(c => c.hex.toUpperCase() === hex.toUpperCase());
            upd("colorId", conocido ? conocido.id : "personalizado");
            upd("colorName", conocido ? conocido.name : hex.toUpperCase());
            upd("colorHex", hex.toUpperCase());
          }}
        />
        <div className="color-grid">
          {D.presetColors.map(c => (
            <button key={c.id} type="button"
              className={"color-swatch " + (tier.colorId === c.id ? "active" : "")}
              onClick={() => {
                upd("colorId", c.id);
                upd("colorName", c.name);
                upd("colorHex", c.hex);
              }}>
              <i style={{background: c.hex}} />
              <span>{c.name}</span>
            </button>
          ))}
        </div>
      </Field>

      <div className="grid-2">
        <Field label="Código Pantone">
          <Input value={tier.pantone} onChange={e => upd("pantone", e.target.value)} placeholder="281 C, etc." />
        </Field>
        <Field label="Especificaciones especiales" full>
          <TextArea rows={2} value={tier.special} onChange={e => upd("special", e.target.value)} placeholder="Detalles adicionales del piso" />
        </Field>
      </div>
    </div>
  );
}

function TiersForm({ s, set, D }) {
  return (
    <SectionCard title="Especificaciones por piso" num="04">
      {s.cake.tiers.map((t, i) => (
        <TierEditor key={i} tier={t} idx={i} set={set} D={D} sameForAll={s.cake.sameForAll} />
      ))}
    </SectionCard>
  );
}

// ========== Extras: topper, figuras, flores ==========
function ExtrasForm({ s, set, D }) {
  return (
    <SectionCard title="Decoraciones y extras" num="05">
      <div className="block-group">
        <h4 className="group-title">Cake topper</h4>
        <Toggle checked={s.cake.topper.enabled} onChange={v => set("cake.topper.enabled", v)} label={IS_CLIENT ? "Incluir cake topper" : `Incluir cake topper (+${fmt(D.extras.cake_topper.price)})`} />
        {s.cake.topper.enabled && (
          <>
            <div className="grid-2">
              <Field label="Nombre o leyenda" full>
                <Input value={s.cake.topper.text} onChange={e => set("cake.topper.text", e.target.value)} placeholder="Ej. NO. 2 Psicóloga Paty Chanona <3" />
              </Field>
              <Field label="Material / estilo / tamaño">
                <Input value={s.cake.topper.material} onChange={e => set("cake.topper.material", e.target.value)} placeholder="Acrílico dorado, 12cm..." />
              </Field>
            </div>
            <div className="grid-2">
              <Field label="Corte de papel">
                <Toggle checked={s.cake.topper.paper} onChange={v => set("cake.topper.paper", v)} label="Sí" />
              </Field>
              <Field label="Corte láser">
                <Toggle checked={s.cake.topper.laser} onChange={v => set("cake.topper.laser", v)} label="Sí" />
              </Field>
            </div>
            {s.cake.topper.laser && (
              <Field label="Si es corte láser, ¿qué color?">
                <Input value={s.cake.topper.laserColor} onChange={e => set("cake.topper.laserColor", e.target.value)} placeholder="Dorado, plata, negro..." />
              </Field>
            )}
          </>
        )}
      </div>

      <div className="block-group">
        <h4 className="group-title">Figuras</h4>
        <div className="extras-counters">
          <CounterRow label="Figuras tipo Funko" price={D.extras.figura_funko.price}
            value={s.cake.figures.funkoQty} onChange={v => set("cake.figures.funkoQty", v)} />
          <CounterRow label="Figuras detalladas" price={D.extras.figura_detalle.price}
            value={s.cake.figures.detailQty} onChange={v => set("cake.figures.detailQty", v)} />
          <CounterRow label="Galletas royal icing simples" price={D.extras.galleta_simple.price}
            value={s.cake.figures.cookieQty} onChange={v => set("cake.figures.cookieQty", v)} />
          <CounterRow label="Galletas royal icing detalladas" price={D.extras.galleta_detalle.price}
            value={s.cake.figures.cookieDetailQty} onChange={v => set("cake.figures.cookieDetailQty", v)} />
        </div>
        <div className="grid-2">
          <Toggle checked={s.cake.figures.fondant3d} onChange={v => set("cake.figures.fondant3d", v)} label="Fondant 3D (sí/no)" />
          <Toggle checked={s.cake.figures.arroz} onChange={v => set("cake.figures.arroz", v)} label="2D sobre arroz" />
          <Toggle checked={s.cake.figures.impreso} onChange={v => set("cake.figures.impreso", v)} label="Impreso" />
          <Toggle checked={s.cake.figures.relieve} onChange={v => set("cake.figures.relieve", v)} label="Relieve" />
        </div>
      </div>

      <div className="block-group">
        <h4 className="group-title">Flores</h4>
        <CounterRow label="Flores decorativas" price={D.extras.flor.price}
          value={s.cake.flowers.qty} onChange={v => set("cake.flowers.qty", v)} />
        <div className="grid-2">
          <Toggle checked={s.cake.flowers.fondant} onChange={v => set("cake.flowers.fondant", v)} label="Azúcar / Fondant" />
          <Toggle checked={s.cake.flowers.natural} onChange={v => set("cake.flowers.natural", v)} label="Naturales" />
        </div>
        <Field label="Color de las flores">
          <Input value={s.cake.flowers.color} onChange={e => set("cake.flowers.color", e.target.value)} placeholder="Ej. Amarillo y azul" />
        </Field>
      </div>

      <div className="block-group">
        <h4 className="group-title">Comentarios y notas adicionales</h4>
        <Field label="Comentarios" full>
          <TextArea rows={3} value={s.notes} onChange={e => set("notes", e.target.value)} placeholder="Cualquier indicación adicional..." />
        </Field>
      </div>
    </SectionCard>
  );
}

function CounterRow({ label, price, value, onChange }) {
  return (
    <div className="counter-row">
      <div className="counter-info">
        <span className="counter-label">{label}</span>
        {!IS_CLIENT && <span className="counter-price">{fmt(price)} c/u</span>}
      </div>
      <div className="counter-ctrl">
        <button type="button" onClick={() => onChange(Math.max(0, (value || 0) - 1))}>−</button>
        <span>{value || 0}</span>
        <button type="button" onClick={() => onChange((value || 0) + 1)}>+</button>
      </div>
    </div>
  );
}

// ========== Cierre: anticipo + impresión (admin) / envío de solicitud (cliente) ==========
function CierreForm({ s, set, totals, onPrint, onPdf, onTab, onSave, saving, saveResult, saveError, editando, onFotoChange, fotoNombre }) {
  if (IS_CLIENT) {
    return (
      <SectionCard title="Enviar solicitud" num="06">
        <p className="field-hint" style={{ marginBottom: 14 }}>
          Con esto ya tenemos todo lo que necesitamos. Nuestro equipo revisará tu solicitud
          y te compartirá el precio y los detalles finales por WhatsApp o llamada.
        </p>
        <Field label="Foto de referencia (opcional)" hint="Si tienes una imagen de inspiración para tu pastel, compártela aquí">
          <input type="file" accept="image/jpeg,image/png,image/webp" className="input"
            onChange={e => onFotoChange && onFotoChange(e.target.files?.[0] || null)} />
          {fotoNombre && <span className="field-hint">Seleccionaste: {fotoNombre}</span>}
        </Field>
        <div className="actions">
          <button className="btn primary" type="button" onClick={onSave} disabled={saving}>
            {saving ? "Enviando…" : "✉  Enviar solicitud de cotización"}
          </button>
        </div>
        {saveResult && (
          <div className="totals-preview" style={{ marginTop: 8 }}>
            <Line label="Listo, recibimos tu solicitud · N.º" value={saveResult.folio} grand />
            <p className="field-hint" style={{ marginTop: 10 }}>
              No necesitas guardar ni buscar nada: nuestro equipo ya tiene tu solicitud y te
              va a contactar directamente por WhatsApp o por llamada con el precio y los
              detalles finales.
            </p>
          </div>
        )}
        {saveResult && saveResult.whatsapp_url && (
          <div className="actions" style={{ marginTop: 12 }}>
            <a className="btn primary" href={saveResult.whatsapp_url} target="_blank" rel="noopener noreferrer">
              📲  Escribirnos ahora por WhatsApp
            </a>
          </div>
        )}
        {saveError && (
          <div className="totals-preview" style={{ marginTop: 8, color: "#c0392b" }}>
            {saveError}
          </div>
        )}
      </SectionCard>
    );
  }

  return (
    <SectionCard title="Cierre y cotización" num="06">
      <div className="grid-2">
        <Field label="Anticipo (manual)" hint={`No puede superar el total (${fmt(totals.total)})`}>
          <Input type="number" min="0" max={totals.total} step="0.01" value={s.advance}
            onChange={e => set("advance", clampNum(e.target.value, 0, totals.total))} />
        </Field>
        <Field label="Folio de cotización">
          <Input value={s.folio} onChange={e => set("folio", e.target.value)} />
        </Field>
      </div>

      <div className="totals-preview">
        <Line label={`Pastel base · ${s.cake.people} personas × ${fmt(window.DEUS_DATA.pricePerPerson(s.cake.people))}`} value={fmt(totals.cakeBase)} />
        {totals.specialPct > 0 && <Line label={`Sabores/rellenos especiales (+${Math.round(totals.specialPct*100)}%)`} value={fmt(totals.specialSurcharge)} />}
        <Line label={`Extras (${totals.extrasCount})`} value={fmt(totals.extrasSum)} />
        <Line label="Envío" value={fmt(totals.shipping)} />
        <Line label="Subtotal" value={fmt(totals.subtotal)} bold />
        <Line label="IVA 16%" value={fmt(totals.iva)} />
        <Line label="Total" value={fmt(totals.total)} grand />
        {totals.advance > 0 && (
          <>
            <Line label="Anticipo" value={fmt(totals.advance)} />
            <Line label="Saldo a pagar" value={fmt(totals.balance)} grand alt />
          </>
        )}
      </div>

      <div className="actions">
        <button className="btn primary" type="button" onClick={() => onTab("resumen")}>Ver cotización</button>
        <button className="btn primary" type="button" onClick={() => onTab("cliente")}>Orden Cliente</button>
        <button className="btn primary" type="button" onClick={() => onTab("cocina")}>Orden Cocina</button>
        <button className="btn primary" type="button" onClick={() => onTab("reparto")}>Orden Reparto</button>
      </div>
      <div className="actions">
        <button className="btn dark" type="button" onClick={onPrint}>🖨  Imprimir documento actual</button>
        <button className="btn dark" type="button" onClick={onPdf}>⬇  Guardar PDF</button>
      </div>
      {editando && (
        <p className="field-hint" style={{ marginBottom: 8 }}>
          ✏ Estás editando una cotización ya guardada — "Guardar" actualiza esta misma cotización, no crea una nueva.
        </p>
      )}
      <div className="actions">
        <button className="btn primary" type="button" onClick={onSave} disabled={saving}>
          {saving ? (editando ? "Actualizando…" : "Guardando…") : (editando ? "💾  Actualizar cotización" : "💾  Guardar cotización en el sistema")}
        </button>
      </div>
      {saveResult && (
        <div className="totals-preview" style={{ marginTop: 8 }}>
          <Line label={`${editando ? "Actualizada" : "Guardada"} con folio ${saveResult.folio}`} value={fmt(saveResult.total)} grand />
        </div>
      )}
      {saveError && (
        <div className="totals-preview" style={{ marginTop: 8, color: "#c0392b" }}>
          {saveError}
        </div>
      )}
    </SectionCard>
  );
}

function Line({ label, value, bold, grand, alt }) {
  return (
    <div className={"line " + (bold ? "bold " : "") + (grand ? "grand " : "") + (alt ? "alt " : "")}>
      <span>{label}</span>
      <strong>{value}</strong>
    </div>
  );
}

Object.assign(window, { ClienteForm, EntregaForm, CakeGeneralForm, TiersForm, ExtrasForm, CierreForm });
