/* global React, ReactDOM */
// ProjectAdvisor — Asesor Interactivo de Proyecto. Reemplaza a LeadModal.jsx.
// Recorre: entrada → árbol (landing/corporativo/ecommerce/sistema/discovery)
// → resumen → estimación → inversión → comparación → (scope-down opcional)
// → resumen final → contacto → confirmación.
//
// Sin imports de Vue ni de ES modules: usa los globals ya cargados por
// pricingConfig.js / flows.js / engine.js (window.BATAJ_*), y React puro.

const { useState, useEffect, useMemo, useRef, useCallback } = React;

const WHATSAPP_NUMBER = '5491157623850';

function buildWhatsappMessage(projectType, answers, estimate) {
  const service = window.BATAJ_PRICING_SEED.services[projectType];
  const label = service ? service.label : projectType;
  const min = estimate ? estimate.min.toLocaleString('es-AR') : '';
  const max = estimate ? estimate.max.toLocaleString('es-AR') : '';
  return `Hola, quiero avanzar con mi proyecto: ${label}. Inversión estimada: ARS ${min} - ${max}. Vengo del Asesor de Proyecto de la web.`;
}

function timelineWeeks(projectType, selectionCount) {
  const base = { landing: [2, 3], corporativo: [3, 5], ecommerce: [4, 8], sistema: [6, 12] }[projectType] || [2, 4];
  const bump = selectionCount >= 8 ? 1 : 0;
  return [base[0] + bump, base[1] + bump];
}

function complexityDots(answers) {
  let n = 0;
  Object.values(answers).forEach((v) => {
    if (Array.isArray(v)) n += v.length; else if (v) n += 1;
  });
  const level = n >= 8 ? 5 : n >= 6 ? 4 : n >= 4 ? 3 : n >= 2 ? 2 : 1;
  return '●'.repeat(level) + '○'.repeat(5 - level);
}

function fmtMoney(n) {
  return 'ARS ' + Math.round(n).toLocaleString('es-AR');
}

function ProjectAdvisor() {
  const [isOpen, setIsOpen] = useState(false);
  const [pricing, setPricing] = useState(window.BATAJ_PRICING_SEED);
  const [phase, setPhase] = useState('entry');
  const [projectType, setProjectType] = useState(null);
  const [stepIndex, setStepIndex] = useState(0);
  const [answers, setAnswers] = useState({});
  const [pendingMulti, setPendingMulti] = useState([]);
  const [pendingText, setPendingText] = useState('');
  const [budgetBand, setBudgetBand] = useState(null);
  const [budgetMatch, setBudgetMatch] = useState(null);
  const [scopeRemoved, setScopeRemoved] = useState({}); // "field:value" -> true
  const [contact, setContact] = useState({ name: '', business: '', contact: '', role: '', stage: '', start_when: '', comment: '' });
  const [sending, setSending] = useState(false);
  const [chosenReadySystem, setChosenReadySystem] = useState(null);
  const [subscriptionTier, setSubscriptionTier] = useState(null);
  const [leadId, setLeadId] = useState(null);
  const [payState, setPayState] = useState('idle'); // idle | loading | error
  const [payError, setPayError] = useState('');
  const [couponInput, setCouponInput] = useState('');
  const [couponCode, setCouponCode] = useState('');
  const [couponPercent, setCouponPercent] = useState(0);
  const [couponState, setCouponState] = useState('idle'); // idle | checking | valid | invalid
  const pendingMultiRef = useRef([]);
  const engine = window.BATAJ_ADVISOR_ENGINE;

  useEffect(() => {
    fetch('/api/pricing.php')
      .then((r) => (r.ok ? r.json() : null))
      .then((data) => { if (data && data.services) setPricing(data); })
      .catch(() => {});
  }, []);

  // El asesor ya no tiene botón propio: lo abre la navbar (y cualquier CTA del
  // sitio) disparando este evento. Ver openAdvisor() en app.jsx.
  useEffect(() => {
    const onOpen = () => setIsOpen(true);
    window.addEventListener('bataj:open-advisor', onOpen);
    return () => window.removeEventListener('bataj:open-advisor', onOpen);
  }, []);

  useEffect(() => {
    if (!isOpen) return;
    const onKeydown = (e) => { if (e.key === 'Escape') close(); };
    window.addEventListener('keydown', onKeydown);
    return () => window.removeEventListener('keydown', onKeydown);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isOpen]);

  const close = useCallback(() => {
    setIsOpen(false);
    setTimeout(() => {
      setPhase('entry'); setProjectType(null); setStepIndex(0); setAnswers({});
      setPendingMulti([]); setPendingText(''); setBudgetBand(null); setBudgetMatch(null);
      setScopeRemoved({}); setContact({ name: '', business: '', contact: '', role: '', stage: '', start_when: '', comment: '' });
      setChosenReadySystem(null); setSubscriptionTier(null); setLeadId(null); setPayState('idle'); setPayError('');
    }, 250);
  }, []);

  const currentFlow = projectType && projectType !== 'discovery' ? window.BATAJ_ADVISOR_FLOWS[projectType] : window.BATAJ_ADVISOR_FLOWS.discovery;
  const currentStep = phase === 'tree' && currentFlow ? currentFlow[stepIndex] : null;

  // Recompute selection state (pendingMulti/pendingText) whenever the step changes.
  useEffect(() => {
    if (!currentStep) return;
    if (currentStep.type === 'multiple') {
      const initial = answers[currentStep.id] || [];
      pendingMultiRef.current = initial;
      setPendingMulti(initial);
    }
    if (currentStep.type === 'text') setPendingText(answers[currentStep.id] || '');
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [phase, stepIndex, projectType]);

  const effectiveAnswers = useMemo(() => {
    if (!Object.keys(scopeRemoved).length) return answers;
    const copy = { ...answers };
    Object.keys(copy).forEach((k) => {
      if (Array.isArray(copy[k])) {
        copy[k] = copy[k].filter((v) => !scopeRemoved[`${k}:${v}`]);
      }
    });
    return copy;
  }, [answers, scopeRemoved]);

  const resolvedProjectType = projectType === 'discovery'
    ? (window.BATAJ_DISCOVERY_ROUTING[answers.limitante] || 'landing')
    : projectType;

  // Sin descontar — esto es lo que se manda a lead.php. El descuento real se
  // aplica y se valida server-side a partir de coupon_code, nunca acá: si
  // horneáramos el % directo en lo que viaja al server, cualquiera podría
  // simular un cupón inventado y pagar de menos en la seña de Mercado Pago.
  const rawEstimate = useMemo(() => {
    if (!resolvedProjectType || resolvedProjectType === 'discovery') return null;
    return engine.computeEstimate(resolvedProjectType, effectiveAnswers, pricing);
  }, [resolvedProjectType, effectiveAnswers, pricing]);

  // Con descuento — solo para lo que ve el usuario en pantalla.
  const estimate = useMemo(() => {
    if (!rawEstimate || !couponPercent) return rawEstimate;
    const factor = (100 - couponPercent) / 100;
    return {
      ...rawEstimate,
      min: engine.round10k(rawEstimate.min * factor),
      max: engine.round10k(rawEstimate.max * factor),
    };
  }, [rawEstimate, couponPercent]);

  async function applyCoupon() {
    const code = couponInput.trim();
    if (!code || couponState === 'checking') return;
    setCouponState('checking');
    try {
      const res = await fetch('/api/coupon-apply.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ code }),
      });
      const data = await res.json().catch(() => null);
      if (data && data.valid) {
        setCouponCode(code);
        setCouponPercent(data.percent || 0);
        setCouponState('valid');
      } else {
        setCouponCode('');
        setCouponPercent(0);
        setCouponState('invalid');
      }
    } catch (err) {
      setCouponCode('');
      setCouponPercent(0);
      setCouponState('invalid');
    }
  }

  function isDiscoveryFlow() {
    return projectType === 'discovery' && currentFlow === window.BATAJ_ADVISOR_FLOWS.discovery;
  }

  function goNextStep(nextAnswers) {
    const flow = isDiscoveryFlow() ? window.BATAJ_ADVISOR_FLOWS.discovery : window.BATAJ_ADVISOR_FLOWS[projectType];
    if (stepIndex + 1 < flow.length) {
      setStepIndex(stepIndex + 1);
      return;
    }
    if (isDiscoveryFlow()) {
      setPhase('discoveryResolved');
      return;
    }
    setPhase('summary');
  }

  function answerSingle(step, value) {
    const next = { ...answers, [step.id]: value };
    setAnswers(next);
    goNextStep(next);
  }
  function toggleMulti(value) {
    setPendingMulti((cur) => {
      const updated = cur.includes(value) ? cur.filter((v) => v !== value) : [...cur, value];
      pendingMultiRef.current = updated;
      return updated;
    });
  }
  function confirmMulti(step) {
    // Lee del ref (siempre al día) en vez del closure de `pendingMulti`, que
    // puede quedar stale si dos clicks caen en el mismo batch de React.
    const next = { ...answers, [step.id]: pendingMultiRef.current };
    setAnswers(next);
    goNextStep(next);
  }
  function confirmText(step) {
    const next = { ...answers, [step.id]: pendingText };
    setAnswers(next);
    goNextStep(next);
  }

  function pickEntry(value) {
    setProjectType(value);
    setStepIndex(0);
    setPhase('tree');
  }

  function confirmDiscoveryRoute() {
    setProjectType(resolvedProjectType);
    setStepIndex(0);
    setPhase('tree');
  }

  function pickBudgetBand(band) {
    setBudgetBand(band);
    const match = engine.classifyBudgetMatch(estimate, band);
    setBudgetMatch(match);
    setPhase('compare');
  }

  function goScopeDown() { setPhase('scopedown'); }

  // Camino reactivo: solo se ofrece cuando el presupuesto no matchea la
  // estimación de un desarrollo a medida — nunca como opción de entrada.
  function goReadySystems() { setPhase('readySystems'); }

  function pickReadySystem(system) {
    setChosenReadySystem(system);
    setPhase('final');
  }

  function backToCompareFromReadySystems() {
    setChosenReadySystem(null);
    setPhase('compare');
  }

  function pickSubscription(tier) {
    setSubscriptionTier(tier.key);
    setPhase('contact');
  }

  function depositBaseAmount() {
    if (chosenReadySystem) return Math.round((chosenReadySystem.priceMin + chosenReadySystem.priceMax) / 2);
    if (estimate) return Math.round((estimate.min + estimate.max) / 2);
    return 0;
  }

  function depositAmount() {
    return Math.round(depositBaseAmount() * (window.BATAJ_DEPOSIT_RATE || 0.3));
  }

  async function startPayment() {
    if (!leadId || payState === 'loading') return;
    setPayState('loading');
    setPayError('');
    const projectLabel = chosenReadySystem ? chosenReadySystem.name : ((pricing.services[resolvedProjectType] || {}).label || 'Proyecto');
    // No mandamos `amount`: checkout-create.php lo recalcula server-side a
    // partir del estimated_min/max que ya quedó guardado en el lead — el
    // valor de acá abajo es solo para mostrarlo en el botón.
    try {
      const res = await fetch('/api/checkout-create.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          lead_id: leadId,
          title: `Anticipo 30% — ${projectLabel} · Bataj Systems`,
        }),
      });
      const data = await res.json().catch(() => null);
      if (!res.ok || !data || !data.init_point) throw new Error((data && data.error) || 'No se pudo generar el link de pago.');
      window.location.href = data.init_point;
    } catch (err) {
      setPayState('error');
      setPayError('No pudimos generar el link de pago ahora. Podés coordinarlo por WhatsApp mientras tanto.');
    }
  }

  function toggleScope(field, value) {
    const key = `${field}:${value}`;
    setScopeRemoved((cur) => {
      const next = { ...cur };
      if (next[key]) delete next[key]; else next[key] = true;
      return next;
    });
  }

  // Recalcula y SIEMPRE avanza. Antes se quedaba en 'scopedown' si el
  // presupuesto seguía corto, lo que dejaba al usuario tocando un botón que
  // no hacía nada visible.
  function continueFromScopeDown() {
    const newEstimate = engine.computeEstimate(resolvedProjectType, effectiveAnswers, pricing);
    setBudgetMatch(engine.classifyBudgetMatch(newEstimate, budgetBand));
    setPhase('final');
  }

  async function submitLead(e) {
    e.preventDefault();
    if (!contact.name.trim() || !contact.contact.trim() || sending) return;
    setSending(true);

    const score = engine.computeScore(
      resolvedProjectType, effectiveAnswers, budgetBand && budgetBand.key, budgetMatch,
      { startWhen: contact.start_when, role: contact.role, stage: contact.stage }
    );
    const qualification = engine.qualify(score);
    const service = pricing.services[resolvedProjectType];
    const weeks = timelineWeeks(resolvedProjectType, Object.keys(effectiveAnswers).length);

    const payload = {
      name: contact.name.trim(),
      business: contact.business.trim(),
      contact: contact.contact.trim(),
      service: chosenReadySystem ? chosenReadySystem.name : (service ? service.label : resolvedProjectType),
      budget: budgetBand ? budgetBand.label : '',
      message: contact.comment.trim(),
      source: 'batajsystems.com · asesor de proyecto',
      project_type: resolvedProjectType,
      objective: Array.isArray(effectiveAnswers.objective) ? effectiveAnswers.objective.join(', ') : (effectiveAnswers.objective || ''),
      complexity: effectiveAnswers.complejidad || effectiveAnswers.nivel_visual || effectiveAnswers.criticidad || '',
      features_json: JSON.stringify(effectiveAnswers.features || effectiveAnswers.funcionalidades || []),
      integrations_json: JSON.stringify(effectiveAnswers.integraciones || []),
      content_status: effectiveAnswers.contenido || '',
      budget_choice: budgetBand ? budgetBand.key : '',
      estimated_min: chosenReadySystem ? chosenReadySystem.priceMin : (rawEstimate ? rawEstimate.min : null),
      estimated_max: chosenReadySystem ? chosenReadySystem.priceMax : (rawEstimate ? rawEstimate.max : null),
      coupon_code: couponPercent > 0 ? couponCode : '',
      timeline_weeks_min: weeks[0],
      timeline_weeks_max: weeks[1],
      start_when: contact.start_when,
      decision_role: contact.role,
      business_stage: contact.stage,
      lead_score: score,
      qualification: qualification.key,
      raw_answers_json: JSON.stringify(effectiveAnswers),
      path_kind: chosenReadySystem ? 'ready_system' : 'custom',
      ready_system_key: chosenReadySystem ? chosenReadySystem.key : '',
      subscription_tier: subscriptionTier || '',
    };

    try {
      const res = await fetch('/api/lead.php', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload),
      });
      const data = await res.json().catch(() => null);
      if (data && data.id) setLeadId(data.id);
    } catch (err) {
      console.warn('[ProjectAdvisor] No se pudo registrar el lead:', err);
    }

    setSending(false);
    setPhase('done');
    window.open(`https://wa.me/${WHATSAPP_NUMBER}?text=${encodeURIComponent(buildWhatsappMessage(resolvedProjectType, effectiveAnswers, estimate))}`, '_blank', 'noopener');
  }

  /* ─────────────────────────  render helpers  ───────────────────────── */

  function OptionCard({ label, hint, onClick, selected }) {
    return (
      <button
        type="button"
        onClick={onClick}
        className="flex flex-col gap-1 rounded-xl border px-4 py-3.5 text-left transition-colors"
        style={{
          borderColor: selected ? 'var(--bataj-accent)' : 'rgba(0,0,0,.1)',
          background: selected ? 'color-mix(in srgb, var(--bataj-accent) 8%, transparent)' : 'transparent',
        }}
      >
        <span className="text-[14px] font-medium text-ink">{label}</span>
        {hint && <span className="text-[12px] text-inkMute">{hint}</span>}
      </button>
    );
  }

  function StepHeader({ title, subtext }) {
    return (
      <div className="mb-5">
        <h3 className="font-display text-[24px] font-medium tracking-tight mb-1.5">{title}</h3>
        {subtext && <p className="text-[13.5px] text-inkMute">{subtext}</p>}
      </div>
    );
  }

  function BackBar({ onBack }) {
    return (
      <button type="button" onClick={onBack} className="mb-3.5 font-mono text-[11px] tracking-wide text-inkMute transition-colors hover:text-ink">
        ← Volver
      </button>
    );
  }

  function ProgressBar() {
    if (phase !== 'tree' || !currentFlow) return null;
    const pct = Math.round(((stepIndex + 1) / currentFlow.length) * 100);
    return (
      <div className="mb-5">
        <div className="mb-1.5 flex justify-between font-mono text-[10px] uppercase tracking-wide text-inkMute">
          <span>Paso {stepIndex + 1} de {currentFlow.length}</span>
          <span>{pct}%</span>
        </div>
        <div className="h-1 rounded-full bg-ink/10">
          <div className="h-1 rounded-full transition-all" style={{ width: `${pct}%`, background: 'var(--bataj-accent)' }} />
        </div>
      </div>
    );
  }

  function renderEntry() {
    const d = window.BATAJ_ADVISOR_ENTRY;
    return (
      <div>
        <p className="chip mb-4">/ asesor de proyecto</p>
        <StepHeader title={d.question} subtext={d.subtext} />
        <div className="grid grid-cols-1 sm:grid-cols-2 gap-2.5">
          {d.options.map((o) => (
            <OptionCard key={o.value} label={o.label} hint={o.hint} onClick={() => pickEntry(o.value)} />
          ))}
        </div>
      </div>
    );
  }

  function renderTreeStep() {
    const step = currentStep;
    if (!step) return null;
    return (
      <div>
        {(stepIndex > 0 || !isDiscoveryFlow()) && (
          <BackBar onBack={() => { if (stepIndex === 0) { setProjectType(null); setPhase('entry'); } else setStepIndex(stepIndex - 1); }} />
        )}
        <ProgressBar />
        <StepHeader title={step.question} subtext={step.subtext} />

        {step.type === 'single' && (
          <div className="flex flex-col gap-2.5">
            {step.options.map((o) => (
              <OptionCard key={o.value} label={o.label} hint={o.hint} selected={answers[step.id] === o.value} onClick={() => answerSingle(step, o.value)} />
            ))}
          </div>
        )}

        {step.type === 'multiple' && (
          <>
            <div className="flex flex-col gap-2.5 mb-5 max-h-[320px] overflow-y-auto pr-1">
              {step.options.map((o) => {
                const sel = pendingMulti.includes(o.value);
                return (
                  <button
                    type="button" key={o.value} onClick={() => toggleMulti(o.value)}
                    className="flex items-center gap-3 rounded-xl border px-4 py-3 text-left"
                    style={{ borderColor: sel ? 'var(--bataj-accent)' : 'rgba(0,0,0,.1)', background: sel ? 'color-mix(in srgb, var(--bataj-accent) 8%, transparent)' : 'transparent' }}
                  >
                    <span className="grid h-4 w-4 flex-shrink-0 place-items-center rounded border" style={{ borderColor: sel ? 'var(--bataj-accent)' : 'rgba(0,0,0,.25)', background: sel ? 'var(--bataj-accent)' : 'transparent' }}>
                      {sel && <span style={{ color: '#fff', fontSize: 10, lineHeight: 1 }}>✓</span>}
                    </span>
                    <span className="text-[13.5px] font-medium text-ink">{o.label}</span>
                  </button>
                );
              })}
            </div>
            <button type="button" className="btn btn-dark w-full" onClick={() => confirmMulti(step)}>Continuar →</button>
          </>
        )}

        {step.type === 'text' && (
          <>
            <textarea
              value={pendingText}
              onChange={(e) => setPendingText(e.target.value)}
              placeholder="Escribí acá..."
              rows={4}
              className="mb-5 w-full rounded-xl border border-ink/10 bg-transparent p-3.5 text-[14px] text-ink placeholder:text-ink/30 focus:border-ink/40 focus:outline-none"
            />
            <button type="button" className="btn btn-dark w-full" onClick={() => confirmText(step)} disabled={!pendingText.trim()}>Continuar →</button>
          </>
        )}
      </div>
    );
  }

  // Lo que el sistema "entendió": las selecciones múltiples + las respuestas
  // diagnósticas. No incluye single-selects de pricing (leen raro en una lista).
  function understoodItems() {
    const flow = window.BATAJ_ADVISOR_FLOWS[resolvedProjectType] || [];
    const out = [];
    flow.forEach((step) => {
      const val = effectiveAnswers[step.id];
      if (val == null || val === '') return;
      if (Array.isArray(val)) {
        val.forEach((v) => out.push(engine.labelFor(resolvedProjectType, step.id, v)));
      } else if (step.type === 'single' && step.kind === 'diagnostic') {
        out.push(engine.labelFor(resolvedProjectType, step.id, val));
      }
    });
    return out;
  }

  const ESTIMATE_DISCLAIMER = 'Estimación inicial. La propuesta final se confirma después de revisar el alcance con vos.';

  function renderDiscoveryResolved() {
    const service = pricing.services[resolvedProjectType];
    const insight = (window.BATAJ_DISCOVERY_INSIGHT || {})[answers.limitante];
    return (
      <div>
        <p className="chip mb-4">/ diagnóstico</p>
        <h3 className="font-display text-[24px] font-medium tracking-tight mb-3">Entendimos tu problema</h3>
        {insight && <p className="text-[15px] text-ink/85 leading-[1.55] mb-5">{insight}</p>}

        <div className="mb-6 rounded-xl border border-ink/10 p-5">
          <p className="font-mono text-[10.5px] uppercase tracking-wide text-inkMute mb-2">La solución que probablemente necesitás</p>
          <div className="font-display text-[22px] font-medium mb-2">{service ? service.label : resolvedProjectType}</div>
          <p className="text-[12.5px] text-inkMute">Ahora definimos el alcance para poder estimarlo.</p>
        </div>

        <button type="button" className="btn btn-dark w-full" onClick={confirmDiscoveryRoute}>Ver cómo lo resolveríamos →</button>
      </div>
    );
  }

  function renderSummary() {
    const service = pricing.services[resolvedProjectType];
    const list = understoodItems();

    return (
      <div>
        <p className="chip mb-4">/ tu proyecto está tomando forma</p>
        <h3 className="font-display text-[24px] font-medium tracking-tight mb-4">{service ? service.label : ''}</h3>
        {list.length > 0 && (
          <>
            <p className="font-mono text-[10.5px] uppercase tracking-wide text-inkMute mb-2">Lo que entendimos</p>
            <ul className="mb-5 flex flex-col gap-1.5">
              {list.map((label, i) => (
                <li key={label + i} className="flex items-start gap-2 text-[13.5px] text-ink/85">
                  <span className="flex-shrink-0" style={{ color: 'var(--bataj-accent)' }}>✓</span>{label}
                </li>
              ))}
            </ul>
          </>
        )}
        <div className="mb-6 rounded-xl p-4" style={{ background: 'color-mix(in srgb, var(--bataj-accent) 8%, transparent)' }}>
          <p className="font-mono text-[10.5px] uppercase tracking-wide mb-1" style={{ color: 'var(--bataj-accent)' }}>¿Por qué importa esto?</p>
          <p className="text-[13px] text-ink/85 leading-[1.5]">
            El alcance, las conexiones con otras herramientas y el nivel de personalización definen el trabajo real detrás del proyecto — no se cotiza por "cantidad de páginas".
          </p>
        </div>
        <button type="button" className="btn btn-dark w-full" onClick={() => setPhase('budget')}>Continuar con la estimación →</button>
      </div>
    );
  }

  function renderBudget() {
    return (
      <div>
        <p className="chip mb-4">/ inversión</p>
        <h3 className="font-display text-[24px] font-medium tracking-tight mb-1.5">Inversión estimada</h3>
        <div className="mb-2 font-display text-[32px] font-medium" style={{ color: 'var(--bataj-accent)' }}>
          {estimate ? `${fmtMoney(estimate.min)} – ${fmtMoney(estimate.max)}` : '—'}
        </div>
        <p className="text-[12.5px] text-inkMute mb-4">
          El rango contempla diseño, desarrollo, implementación y puesta en producción del alcance que definimos.
        </p>
        <p className="text-[11.5px] text-inkMute/80 mb-6 leading-[1.5]">
          <b className="text-ink/70">¿Qué puede hacer variar el valor?</b> Conexiones con otras herramientas, el contenido,
          funcionalidades adicionales o cambios de alcance.
        </p>

        <div className="mb-6">
          {couponState === 'valid' ? (
            <p className="text-[12.5px] font-medium" style={{ color: 'var(--live, #2E7D32)' }}>
              ✓ Cupón "{couponCode}" aplicado — {couponPercent}% off
            </p>
          ) : (
            <>
              <div className="flex gap-2">
                <input
                  type="text"
                  value={couponInput}
                  onChange={(e) => { setCouponInput(e.target.value); if (couponState === 'invalid') setCouponState('idle'); }}
                  placeholder="¿Tenés un código de descuento?"
                  className="flex-1 text-[13px] px-3 py-2 rounded-lg border"
                  style={{ borderColor: 'var(--line, #ddd)' }}
                />
                <button
                  type="button"
                  className="btn btn-ghost"
                  disabled={!couponInput.trim() || couponState === 'checking'}
                  onClick={applyCoupon}
                >
                  {couponState === 'checking' ? 'Validando…' : 'Aplicar'}
                </button>
              </div>
              {couponState === 'invalid' && (
                <p className="text-[11.5px] mt-1.5" style={{ color: 'var(--danger, #C0392B)' }}>Ese código no es válido.</p>
              )}
            </>
          )}
        </div>

        <p className="text-[14px] font-medium text-ink mb-1">¿Qué nivel de inversión tenías previsto?</p>
        <p className="text-[12px] text-inkMute mb-3">No cambia el precio: nos sirve para saber si conviene arrancar por una primera etapa.</p>
        <div className="flex flex-col gap-2.5 mb-2">
          {pricing.budgetBands.map((b) => (
            <OptionCard key={b.key} label={`${b.label} · ${fmtMoney(b.min)}${b.max ? ' – ' + fmtMoney(b.max) : '+'}`} hint={b.hint} onClick={() => pickBudgetBand(b)} />
          ))}
          <OptionCard label="Todavía no lo sé" hint="Quiero entender primero qué necesito." onClick={() => pickBudgetBand({ key: 'unsure', label: 'A definir', min: 0, max: null })} />
        </div>
      </div>
    );
  }

  function renderCompare() {
    const copy = {
      match: {
        title: 'Tu presupuesto está dentro del rango',
        body: 'Podemos encarar el proyecto completo con el alcance que definimos.',
      },
      flexible: {
        title: 'Estamos cerca',
        body: 'Podemos priorizar las funcionalidades principales y dejar algunas mejoras para una segunda etapa.',
      },
      below: {
        title: 'Podemos construir una primera versión',
        body: 'Con ese presupuesto arrancamos por lo que resuelve tu objetivo principal, y el resto queda planificado para una segunda etapa.',
      },
      unknown: {
        title: 'Sin problema',
        body: 'El objetivo de esta estimación es justamente ayudarte a entender qué inversión requiere el proyecto.',
      },
    }[budgetMatch] || {};

    const needsPhasing = budgetMatch === 'below' || budgetMatch === 'flexible';
    const readySystemsForType = (window.BATAJ_READY_SYSTEMS && window.BATAJ_READY_SYSTEMS[resolvedProjectType]) || [];
    const offerReadySystems = needsPhasing && readySystemsForType.length > 0;

    return (
      <div className="text-center">
        <p className="chip mb-4">/ alcance</p>
        <h3 className="font-display text-[24px] font-medium tracking-tight mb-2">{copy.title}</h3>
        <p className="text-[14px] text-inkMute mb-7">{copy.body}</p>
        {needsPhasing ? (
          <div className="flex flex-col gap-2.5">
            <button type="button" className="btn btn-dark w-full" onClick={goScopeDown}>Ver qué podemos priorizar</button>
            {offerReadySystems && (
              <button type="button" className="btn btn-ghost w-full" onClick={goReadySystems}>Ver sistemas ya armados y funcionando</button>
            )}
            <button type="button" className="btn btn-ghost w-full" onClick={() => setPhase('final')}>Continuar con el alcance completo</button>
          </div>
        ) : (
          <button type="button" className="btn btn-dark w-full" onClick={() => setPhase('final')}>Continuar →</button>
        )}
      </div>
    );
  }

  function renderReadySystems() {
    const systems = (window.BATAJ_READY_SYSTEMS && window.BATAJ_READY_SYSTEMS[resolvedProjectType]) || [];
    return (
      <div>
        <BackBar onBack={backToCompareFromReadySystems} />
        <p className="chip mb-4">/ sistemas ya armados</p>
        <h3 className="font-display text-[24px] font-medium tracking-tight mb-1.5">Ya tenemos algo funcionando que puede servirte</h3>
        <p className="text-[13.5px] text-inkMute mb-5">
          Son sistemas reales, en producción hoy. Los adaptamos a tu marca y contenido — no se construyen desde cero, por eso cuestan menos y se entregan más rápido.
        </p>
        <div className="flex flex-col gap-3">
          {systems.map((s) => (
            <div key={s.key} className="rounded-xl border border-ink/10 p-4">
              <div className="flex items-baseline justify-between gap-3 mb-1">
                <span className="font-display text-[17px] font-medium">{s.name}</span>
                <a href={s.url} target="_blank" rel="noreferrer" className="font-mono text-[11px] tracking-wide flex-shrink-0" style={{ color: 'var(--bataj-accent)' }}>
                  Ver sitio real ↗
                </a>
              </div>
              <p className="text-[12.5px] text-inkMute mb-3">{s.note}</p>
              <div className="flex items-center justify-between gap-3">
                <span className="font-mono text-[13px] font-medium text-ink">{fmtMoney(s.priceMin)} – {fmtMoney(s.priceMax)}</span>
                <button type="button" className="btn btn-dark" onClick={() => pickReadySystem(s)}>Elegir este →</button>
              </div>
            </div>
          ))}
        </div>
      </div>
    );
  }

  function renderScopeDown() {
    const split = engine.buildScopeSplit(resolvedProjectType, answers, pricing);
    const full = engine.computeEstimate(resolvedProjectType, answers, pricing);
    const postponedCount = Object.keys(scopeRemoved).length;

    return (
      <div>
        <p className="chip mb-4">/ optimizar alcance</p>
        <h3 className="font-display text-[24px] font-medium tracking-tight mb-1.5">Podemos ajustar el alcance sin comprometer el objetivo</h3>
        <p className="text-[13px] text-inkMute mb-5">Marcá lo que puede esperar a una segunda etapa. El total se recalcula al instante.</p>

        <div className="mb-4">
          <p className="font-mono text-[10.5px] uppercase tracking-wide text-inkMute mb-2">Se mantiene</p>
          {split.keep.length > 0 ? (
            <div className="flex flex-wrap gap-1.5">
              {split.keep.slice(0, 8).map((k, i) => (
                <span key={k.label + i} className="inline-flex items-center gap-1.5 rounded-lg bg-ink/[.04] px-2.5 py-1 text-[12px] text-ink/75">
                  <span style={{ color: 'var(--bataj-accent)' }}>✓</span>{k.label}
                </span>
              ))}
            </div>
          ) : (
            <p className="text-[12.5px] text-inkMute">La base del proyecto y todo lo que no marques acá abajo.</p>
          )}
        </div>

        <p className="font-mono text-[10.5px] uppercase tracking-wide text-inkMute mb-2">Se puede postergar</p>
        <div className="mb-5 flex flex-col gap-2 max-h-[220px] overflow-y-auto pr-1">
          {split.postpone.length === 0 && (
            <p className="text-[13px] text-inkMute">Tu alcance ya es el mínimo: no hay funcionalidades opcionales para postergar.</p>
          )}
          {split.postpone.map((o) => {
            const key = `${o.field}:${o.value}`;
            const removed = !!scopeRemoved[key];
            return (
              <button
                type="button" key={key} onClick={() => toggleScope(o.field, o.value)}
                className="flex items-center justify-between rounded-xl border px-4 py-3 text-left transition-colors"
                style={{ borderColor: removed ? 'rgba(0,0,0,.08)' : 'rgba(0,0,0,.14)', opacity: removed ? 0.5 : 1 }}
              >
                <span className="flex items-center gap-2 text-[13px]" style={{ textDecoration: removed ? 'line-through' : 'none' }}>
                  <span className="font-mono text-[12px]">{removed ? '☐' : '☑'}</span>{o.label}
                </span>
                <span className="font-mono text-[11.5px] text-inkMute">{removed ? '−' : '+'}{fmtMoney(o.price)}</span>
              </button>
            );
          })}
        </div>

        <div className="mb-5 rounded-xl p-4" style={{ background: 'color-mix(in srgb, var(--bataj-accent) 8%, transparent)' }}>
          <p className="font-mono text-[10.5px] uppercase tracking-wide mb-1" style={{ color: 'var(--bataj-accent)' }}>Nueva estimación</p>
          <div className="flex items-baseline gap-2 flex-wrap">
            {postponedCount > 0 && (
              <span className="font-mono text-[13px] text-inkMute line-through">{fmtMoney(full.min)} – {fmtMoney(full.max)}</span>
            )}
            <span className="font-display text-[22px] font-medium">
              {estimate ? `${fmtMoney(estimate.min)} – ${fmtMoney(estimate.max)}` : '—'}
            </span>
          </div>
          {postponedCount > 0 && (
            <p className="text-[11.5px] text-inkMute mt-1.5">
              {postponedCount} {postponedCount === 1 ? 'funcionalidad queda' : 'funcionalidades quedan'} para una segunda etapa.
            </p>
          )}
        </div>

        <button type="button" className="btn btn-dark w-full" onClick={continueFromScopeDown}>Continuar con este alcance →</button>
      </div>
    );
  }

  function renderFinal() {
    if (chosenReadySystem) return renderFinalReadySystem();

    const service = pricing.services[resolvedProjectType];
    const weeks = timelineWeeks(resolvedProjectType, Object.keys(effectiveAnswers).length);
    const list = understoodItems();
    const postponedCount = Object.keys(scopeRemoved).length;

    return (
      <div>
        <p className="chip mb-4">/ tu proyecto está definido</p>
        <div className="flex items-baseline justify-between gap-3 mb-5">
          <h3 className="font-display text-[24px] font-medium tracking-tight">{service ? service.label : ''}</h3>
          <span className="font-mono text-[13px] flex-shrink-0" style={{ color: 'var(--bataj-accent)' }}>{complexityDots(effectiveAnswers)}</span>
        </div>

        {list.length > 0 && (
          <div className="mb-5 border-t border-ink/10 pt-4">
            <p className="font-mono text-[10.5px] uppercase tracking-wide text-inkMute mb-2">Lo que entendimos</p>
            <ul className="flex flex-col gap-1.5">
              {list.slice(0, 9).map((label, i) => (
                <li key={label + i} className="flex items-start gap-2 text-[13px] text-ink/85">
                  <span className="flex-shrink-0" style={{ color: 'var(--bataj-accent)' }}>✓</span>{label}
                </li>
              ))}
            </ul>
            {postponedCount > 0 && (
              <p className="mt-3 text-[12px] text-inkMute">
                + {postponedCount} {postponedCount === 1 ? 'funcionalidad planificada' : 'funcionalidades planificadas'} para una segunda etapa.
              </p>
            )}
          </div>
        )}

        <div className="mb-4 rounded-xl p-4 border-t border-ink/10" style={{ background: 'color-mix(in srgb, var(--bataj-accent) 8%, transparent)' }}>
          <p className="font-mono text-[10.5px] uppercase tracking-wide mb-1" style={{ color: 'var(--bataj-accent)' }}>Inversión estimada</p>
          <p className="font-display text-[26px] font-medium">{estimate ? `${fmtMoney(estimate.min)} – ${fmtMoney(estimate.max)}` : '—'}</p>
        </div>

        <div className="mb-4 flex items-center justify-between text-[13px]">
          <span className="text-inkMute">Plazo estimado</span>
          <span className="font-medium text-ink">{weeks[0]}–{weeks[1]} semanas</span>
        </div>

        <p className="text-[11.5px] text-inkMute mb-6 leading-[1.5]">{ESTIMATE_DISCLAIMER}</p>

        <button type="button" className="btn btn-dark w-full" onClick={() => setPhase('subscription')}>Quiero avanzar →</button>
      </div>
    );
  }

  function renderFinalReadySystem() {
    const s = chosenReadySystem;
    return (
      <div>
        <p className="chip mb-4">/ tu proyecto está definido</p>
        <h3 className="font-display text-[24px] font-medium tracking-tight mb-1.5">{s.name}</h3>
        <p className="text-[13.5px] text-inkMute mb-5">{s.note}</p>

        <a href={s.url} target="_blank" rel="noreferrer" className="mb-5 inline-flex items-center gap-1.5 font-mono text-[11.5px] tracking-wide" style={{ color: 'var(--bataj-accent)' }}>
          Ver sitio real ↗
        </a>

        <div className="mb-4 rounded-xl p-4 border-t border-ink/10" style={{ background: 'color-mix(in srgb, var(--bataj-accent) 8%, transparent)' }}>
          <p className="font-mono text-[10.5px] uppercase tracking-wide mb-1" style={{ color: 'var(--bataj-accent)' }}>Inversión</p>
          <p className="font-display text-[26px] font-medium">{fmtMoney(s.priceMin)} – {fmtMoney(s.priceMax)}</p>
        </div>

        <div className="mb-4 flex items-center justify-between text-[13px]">
          <span className="text-inkMute">Plazo estimado</span>
          <span className="font-medium text-ink">Implementación rápida — ya está construido</span>
        </div>

        <p className="text-[11.5px] text-inkMute mb-6 leading-[1.5]">{ESTIMATE_DISCLAIMER}</p>

        <button type="button" className="btn btn-dark w-full" onClick={() => setPhase('subscription')}>Quiero avanzar →</button>
      </div>
    );
  }

  function renderSubscription() {
    const tiers = window.BATAJ_SUBSCRIPTION_TIERS || [];
    return (
      <div>
        <BackBar onBack={() => setPhase('final')} />
        <p className="chip mb-4">/ soporte y mantenimiento</p>
        <h3 className="font-display text-[24px] font-medium tracking-tight mb-1.5">¿Con qué nivel de soporte lo acompañamos?</h3>
        <p className="text-[13.5px] text-inkMute mb-5">
          Todo sistema que ponemos en producción necesita hosting, backups y alguien que responda si algo falla. Elegí el nivel que se ajusta a tu operación.
        </p>
        <div className="flex flex-col gap-2.5">
          {tiers.map((t) => (
            <OptionCard
              key={t.key}
              label={`${t.label} · ${fmtMoney(t.price)}/mes`}
              hint={t.note}
              selected={subscriptionTier === t.key}
              onClick={() => pickSubscription(t)}
            />
          ))}
        </div>
      </div>
    );
  }

  function renderContact() {
    return (
      <form onSubmit={submitLead}>
        <p className="chip mb-4">/ último paso</p>
        <h3 className="font-display text-[24px] font-medium tracking-tight mb-1.5">¿Querés iniciarlo?</h3>
        <p className="text-[13.5px] text-inkMute mb-5">Dejanos tus datos y te llevamos directo a reservar tu lugar con el 30% de anticipo.</p>

        {window.BATAJ_ADVISOR_CONTACT_FIELDS.map((f) => (
          <label key={f.id} className="mb-3.5 flex flex-col gap-1.5">
            <span className="font-mono text-[11px] uppercase tracking-wide text-inkMute">{f.label}</span>
            {f.type === 'select' ? (
              <select
                value={contact[f.id]}
                onChange={(e) => setContact({ ...contact, [f.id]: e.target.value })}
                className="rounded-lg border border-ink/10 bg-transparent px-3.5 py-3 text-[14px] text-ink focus:border-ink/40 focus:outline-none"
              >
                <option value="">Elegir…</option>
                {f.options.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
              </select>
            ) : f.type === 'textarea' ? (
              <textarea
                value={contact[f.id]} onChange={(e) => setContact({ ...contact, [f.id]: e.target.value })}
                placeholder={f.placeholder} rows={3}
                className="rounded-lg border border-ink/10 bg-transparent px-3.5 py-3 text-[14px] text-ink placeholder:text-ink/30 focus:border-ink/40 focus:outline-none"
              />
            ) : (
              <input
                type="text" value={contact[f.id]} onChange={(e) => setContact({ ...contact, [f.id]: e.target.value })}
                placeholder={f.placeholder} required={f.required}
                className="rounded-lg border border-ink/10 bg-transparent px-3.5 py-3 text-[14px] text-ink placeholder:text-ink/30 focus:border-ink/40 focus:outline-none"
              />
            )}
          </label>
        ))}

        <button type="submit" disabled={sending} className="btn btn-dark w-full disabled:pointer-events-none disabled:opacity-50 mt-2">
          {sending ? 'Enviando…' : 'Quiero iniciarlo →'}
        </button>
      </form>
    );
  }

  function renderDone() {
    const service = pricing.services[resolvedProjectType];
    const projectLabel = chosenReadySystem ? chosenReadySystem.name : (service ? service.label : '');
    const priceLine = chosenReadySystem
      ? `${fmtMoney(chosenReadySystem.priceMin)} – ${fmtMoney(chosenReadySystem.priceMax)}`
      : (estimate ? `${fmtMoney(estimate.min)} – ${fmtMoney(estimate.max)}` : '—');
    const tier = (window.BATAJ_SUBSCRIPTION_TIERS || []).find((t) => t.key === subscriptionTier);

    return (
      <div className="text-center">
        <div className="mb-3.5 inline-flex items-center gap-2 font-mono text-[11px] uppercase tracking-wide" style={{ color: 'var(--bataj-accent)' }}>
          <span className="dot pulse" style={{ background: 'var(--bataj-accent)' }} />Recibimos tu proyecto
        </div>
        <h3 className="font-display text-[24px] font-medium tracking-tight mb-4">{leadId ? 'Reservá tu lugar para iniciar' : 'Ya tenemos una primera definición'}</h3>

        {leadId && (
          <div className="mb-5 rounded-xl p-4 text-left" style={{ background: 'color-mix(in srgb, var(--bataj-accent) 8%, transparent)' }}>
            <p className="font-mono text-[10.5px] uppercase tracking-wide mb-1" style={{ color: 'var(--bataj-accent)' }}>Anticipo del 30% para arrancar</p>
            <p className="text-[12.5px] text-ink/80 mb-3">Con el anticipo reservamos el desarrollo y arrancamos a trabajar. El resto se coordina según el avance.</p>
            <button type="button" onClick={startPayment} disabled={payState === 'loading'} className="btn btn-dark w-full disabled:pointer-events-none disabled:opacity-50">
              {payState === 'loading' ? 'Generando link de pago…' : `Pagar el 30% e iniciar (${fmtMoney(depositAmount())})`}
            </button>
            {payState === 'error' && <p className="mt-2 text-[12px]" style={{ color: '#b3261e' }}>{payError}</p>}
          </div>
        )}

        <div className="mb-5 rounded-xl border border-ink/10 p-5 text-left">
          <div className="flex justify-between text-[13px] mb-2"><span className="text-inkMute">Proyecto</span><span className="font-medium text-ink">{projectLabel}</span></div>
          <div className="flex justify-between text-[13px] mb-2"><span className="text-inkMute">Inversión estimada</span><span className="font-medium text-ink">{priceLine}</span></div>
          {tier && (
            <div className="flex justify-between text-[13px] mb-2"><span className="text-inkMute">Soporte mensual</span><span className="font-medium text-ink">{tier.label} · {fmtMoney(tier.price)}/mes</span></div>
          )}
          <div className="flex justify-between text-[13px]"><span className="text-inkMute">Próximo paso</span><span className="font-medium text-ink">{leadId ? 'Confirmar el anticipo' : 'Revisión del alcance'}</span></div>
        </div>

        <p className="text-[12px] text-inkMute mb-6">La estimación es orientativa. El presupuesto definitivo se determina después de revisar los requerimientos y objetivos del proyecto.</p>
        <a
          href={`https://wa.me/${WHATSAPP_NUMBER}?text=${encodeURIComponent(buildWhatsappMessage(resolvedProjectType, effectiveAnswers, estimate))}`}
          target="_blank" rel="noreferrer" className="btn btn-ghost w-full"
        >
          Prefiero coordinarlo por WhatsApp
        </a>
      </div>
    );
  }

  const phaseRenderers = {
    entry: renderEntry,
    tree: renderTreeStep,
    discoveryResolved: renderDiscoveryResolved,
    summary: renderSummary,
    budget: renderBudget,
    compare: renderCompare,
    scopedown: renderScopeDown,
    readySystems: renderReadySystems,
    final: renderFinal,
    subscription: renderSubscription,
    contact: renderContact,
    done: renderDone,
  };

  return (
    <>
      {isOpen &&
        ReactDOM.createPortal(
          <div
            className="fixed inset-0 z-[300] flex items-center justify-center p-5 bg-black/60 backdrop-blur-sm"
            onClick={(e) => e.target === e.currentTarget && close()}
          >
            <div
              role="dialog" aria-modal="true" aria-label="Asesor de proyecto"
              className="neo-card neo-glow relative w-full max-w-[520px] max-h-[88vh] overflow-y-auto rounded-2xl p-8"
            >
              <button
                type="button" aria-label="Cerrar" onClick={close}
                className="absolute top-4 right-4 grid h-8 w-8 place-items-center rounded-full text-inkMute transition-colors hover:bg-ink/5 hover:text-ink"
              >
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
              </button>

              {(phaseRenderers[phase] || renderEntry)()}
            </div>
          </div>,
          document.body
        )}
    </>
  );
}

Object.assign(window, { ProjectAdvisor });
