/* Funnel engine — renders any vertical config (see verticals/*.js + README).
   A config is pure data: brand chrome + an ordered list of typed steps.
   Step types: cards · rows · chips · slider · fields · interstitial · redirect */

const { useState, useEffect, useRef } = React;

/* ---------- input masks + validation ---------- */
function maskValue(mask, raw) {
  const d = raw.replace(/\D/g, '');
  if (mask === 'date') return [d.slice(0, 2), d.slice(2, 4), d.slice(4, 8)].filter(Boolean).join('/');
  if (mask === 'zip') return d.slice(0, 5);
  if (mask === 'phone') {
    if (!d.length) return '';
    if (d.length <= 3) return '(' + d;
    if (d.length <= 6) return `(${d.slice(0, 3)}) ${d.slice(3)}`;
    return `(${d.slice(0, 3)}) ${d.slice(3, 6)}-${d.slice(6, 10)}`;
  }
  return raw;
}
function fieldValid(f, v) {
  v = (v || '').trim();
  if (f.mask === 'date') return /^\d{2}\/\d{2}\/\d{4}$/.test(v);
  if (f.mask === 'zip') return /^\d{5}$/.test(v);
  if (f.mask === 'phone') return v.replace(/\D/g, '').length === 10;
  if (f.mask === 'email') return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v);
  return f.optional ? true : v.length > 0;
}
function fmtSlider(s, v) {
  if (s.maxLabel && v >= s.max) return s.maxLabel;
  return (s.prefix ?? '$') + Number(v).toLocaleString('en-US') + (s.suffix || '');
}
function sliderVal(s, a, key) { return a[key] ?? s.default ?? s.min ?? 0; }

/* ---------- chrome ---------- */
function TopBar({ config }) {
  return (
    <div className="fn-topbar">
      <img className="fn-logo" src={config.logo} alt={config.brandName} />
      <div className="fn-help">
        <span className="q">Need help?</span>
        <a className="ph" href={'tel:' + config.phone.replace(/\D/g, '')}>{config.phone}</a>
      </div>
    </div>
  );
}

function Progress({ steps, stepIdx, done }) {
  const nPhases = 1 + Math.max(...steps.map((s) => s.phase || 0));
  return (
    <div className="fn-progress">
      {Array.from({ length: nPhases }).map((_, p) => {
        const idxs = steps.map((s, i) => [(s.phase || 0), i]).filter(([ph]) => ph === p).map(([, i]) => i);
        let pct = 0;
        if (done || stepIdx > idxs[idxs.length - 1]) pct = 100;
        else if (stepIdx >= idxs[0]) pct = ((idxs.indexOf(stepIdx) + 0.55) / idxs.length) * 100;
        return <div key={p} className="seg"><div className="bar" style={{ width: pct + '%' }}></div></div>;
      })}
    </div>
  );
}

/* ---------- interstitial blocks ---------- */
function Blocks({ blocks }) {
  return blocks.map((b, i) => {
    if (b.type === 'eyebrow') return <Eyebrow key={i}>{b.text}</Eyebrow>;
    if (b.type === 'text') return <p key={i} className="cv-body" style={{ margin: '20px 0 6px' }}>{b.text}</p>;
    if (b.type === 'phases') return (
      <div key={i} className="fn-phases">
        {b.items.map(([t, d], j) => (
          <div key={t} className={'fn-phase' + (j === 0 ? ' active' : '')}>
            <span className="num">{j + 1}</span>
            <div><div className="pt">{t}</div><div className="pd">{d}</div></div>
          </div>
        ))}
      </div>
    );
    if (b.type === 'quote') return (
      <div key={i} className="fn-quote">
        <Stars n={5} />
        <div className="qt">"{b.text}"</div>
        <div className="by">— {b.by}</div>
      </div>
    );
    if (b.type === 'protect') return (
      <div key={i}>
        <Eyebrow>{b.label}</Eyebrow>
        <div className="fn-protect">
          {b.items.map(([l, ic]) => (
            <div key={l} className="pi"><Icon name={ic} size={30} /><div className="pl">{l}</div></div>
          ))}
        </div>
      </div>
    );
    if (b.type === 'benefits') return (
      <div key={i}>
        {b.items.map(([ic, t, d]) => (
          <div className="fn-benefit" key={t}>
            <span className="bic"><Icon name={ic} size={26} /></span>
            <div><div className="bt">{t}</div><div className="bd">{d}</div></div>
          </div>
        ))}
      </div>
    );
    if (b.type === 'stat') return (
      <div key={i} className="fn-stat">
        <div className="big">{b.big}</div>
        <div className="lbl">{b.label}</div>
        {b.note && <div className="note">{b.note}</div>}
      </div>
    );
    return null;
  });
}

/* ---------- step body ---------- */
function Field({ f, a, setField, autoFocus }) {
  const numeric = f.mask === 'date' || f.mask === 'zip' || f.mask === 'phone';
  return (
    <TextField
      label={f.label} placeholder={f.placeholder} autoFocus={autoFocus}
      type={f.mask === 'email' ? 'email' : numeric ? 'tel' : 'text'}
      inputMode={numeric ? 'numeric' : undefined}
      value={a[f.key] || ''} onChange={(v) => setField(f.key, f.mask, v)}
    />
  );
}

function StepBody({ step, ctx }) {
  const { a, toggle, pick, set, setField } = ctx;
  if (step.type === 'cards') {
    const multi = !!step.multi;
    return (
      <div className="fn-cardgrid">
        {step.options.map(([label, icon]) => (
          <OptionCard key={label} icon={icon} label={label}
            selected={multi ? (a[step.key] || []).includes(label) : a[step.key] === label}
            onClick={() => (multi ? toggle(step.key, label) : pick(step.key, label))} />
        ))}
      </div>
    );
  }
  if (step.type === 'rows') return (
    <div className="fn-rows">
      {step.options.map((l) => (
        <OptionRow key={l} label={l} selected={a[step.key] === l} onClick={() => pick(step.key, l)} />
      ))}
    </div>
  );
  if (step.type === 'chips') return (
    <div className="fn-chips">
      {step.options.map((l) => (
        <Chip key={l} label={l} selected={a[step.key] === l} onClick={() => pick(step.key, l)} />
      ))}
    </div>
  );
  if (step.type === 'slider') {
    const s = step.slider;
    const v = sliderVal(s, a, step.key);
    return (
      <div>
        <Slider label={s.label} display={fmtSlider(s, v)} value={v} min={s.min || 0} max={s.max} step={s.step || 1}
          minLabel={s.minLabel ?? fmtSlider(s, s.min || 0)} maxLabel={s.maxLabel || fmtSlider(s, s.max)}
          onChange={(v2) => set(step.key, v2)} />
        {step.callout && <InfoCallout>{step.callout}</InfoCallout>}
      </div>
    );
  }
  if (step.type === 'fields') return (
    <div>
      <div className="fn-fields2">
        {step.fields.map((f, i) => (
          <div key={f.key} style={f.half ? null : { gridColumn: '1 / -1' }}>
            <Field f={f} a={a} setField={setField} autoFocus={i === 0} />
          </div>
        ))}
      </div>
      {step.secure && <div className="fn-secnote"><Icon name="shield" size={15} /> We use secure encryption to protect your data.</div>}
    </div>
  );
  if (step.type === 'interstitial') return <div><Blocks blocks={step.blocks} /></div>;
  return null;
}

/* ---------- mock partner handoff ---------- */
function RedirectScreen({ step, a, config, onRestart }) {
  const [matched, setMatched] = useState(false);
  useEffect(() => { const t = setTimeout(() => setMatched(true), 2000); return () => clearTimeout(t); }, []);
  useEffect(() => { if (window.lucide) window.lucide.createIcons(); }, [matched]);
  const p = step.partner;
  if (!matched) return (
    <div className="fn-screen fn-searching">
      <div className="fn-spin"></div>
      <h1 className="cv-h2">{step.searchTitle || 'Finding your best match…'}</h1>
      <p className="cv-sm" style={{ marginTop: 10 }}>Reviewing your answers against our partner network.</p>
    </div>
  );
  return (
    <div className="fn-screen fn-done">
      <div className="big"><Icon name="check" size={32} /></div>
      <h1 className="cv-h1">{(step.title || "You're matched{name}!").replace('{name}', a.firstName ? ', ' + a.firstName : '')}</h1>
      {step.help && <p className="cv-lead" style={{ marginTop: 12 }}>{step.help}</p>}
      <div className="fn-partner">
        <div className="ph">
          <span className="plogo"><Icon name={p.icon} size={26} /></span>
          <div><div className="pn">{p.name}</div><div className="ptag">{p.tag}</div></div>
          <span className="pbadge">Top match</span>
        </div>
        <ul className="pb">
          {p.bullets.map((b) => <li key={b}><Icon name="check" size={16} /> {b}</li>)}
        </ul>
        <button type="button" className="fn-cta" style={{ marginTop: 20 }} onClick={(e) => e.preventDefault()}>
          Continue to {p.name} <Icon name="arrow-right" size={18} />
        </button>
        <div className="pnote"><Icon name="lock" size={13} /> You'll complete your request on {p.name}'s secure site.</div>
      </div>
      <button type="button" className="fn-ghost" onClick={onRestart}>Restart demo</button>
    </div>
  );
}

/* ---------- app ---------- */
function consentText(config, step) {
  return step.consentText || config.consentText ||
    `By clicking “${step.cta || 'Next'}”, I agree to the Terms of Use and Privacy Policy and consent to be contacted by ${config.brandName} and its marketing partners by phone, text, or email at the contact info provided, including via automated technology. Consent is not a condition of purchase.`;
}

function FunnelApp({ config }) {
  const [stepIdx, setStepIdx] = useState(0);
  const [a, setA] = useState({});
  const advRef = useRef(false);
  const steps = config.steps;
  const cur = steps[stepIdx];
  const isRedirect = cur.type === 'redirect';

  const set = (k, v) => setA((p) => ({ ...p, [k]: v }));
  const toggle = (k, v) => setA((p) => {
    const arr = p[k] || [];
    return { ...p, [k]: arr.includes(v) ? arr.filter((x) => x !== v) : [...arr, v] };
  });
  const next = () => setStepIdx((s) => Math.min(s + 1, steps.length - 1));
  const back = () => setStepIdx((s) => Math.max(0, s - 1));
  /* auto-advance: show the selected state briefly before moving on */
  const pick = (k, v) => {
    if (advRef.current) return;
    advRef.current = true;
    set(k, v);
    setTimeout(() => { advRef.current = false; next(); }, 320);
  };
  const setField = (k, mask, raw) => set(k, maskValue(mask, raw));

  const valid = () => {
    if (cur.type === 'cards' && cur.multi) return (a[cur.key] || []).length > 0;
    if (cur.type === 'fields') return cur.fields.every((f) => fieldValid(f, a[f.key]));
    return true;
  };
  const showCta = !isRedirect && cur.type !== 'rows' && cur.type !== 'chips' && !(cur.type === 'cards' && !cur.multi);

  useEffect(() => { if (window.lucide) window.lucide.createIcons(); }, [stepIdx, a]);
  useEffect(() => {
    const h = (e) => { if (e.key === 'Enter' && showCta && valid()) next(); };
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  });

  return (
    <div>
      <TopBar config={config} />
      <Progress steps={steps} stepIdx={stepIdx} done={isRedirect} />
      <div className="fn-stage">
        {stepIdx > 0 && !isRedirect && (
          <button className="fn-back" onClick={back}><Icon name="arrow-left" size={18} /> Back</button>
        )}
        {isRedirect ? (
          <RedirectScreen key="redirect" step={cur} a={a} config={config}
            onRestart={() => { setA({}); setStepIdx(0); }} />
        ) : (
          <div className="fn-screen" key={cur.key}>
            <h1 className="cv-h1 fn-q">{cur.title}</h1>
            {cur.help && <p className="fn-help-line">{cur.help}</p>}
            <StepBody step={cur} ctx={{ a, set, toggle, pick, setField }} />
            {cur.consent && <p className="fn-consent">{consentText(config, cur)}</p>}
            {showCta && (
              <PrimaryButton disabled={!valid()} onClick={next}>{cur.cta || 'Next'}</PrimaryButton>
            )}
          </div>
        )}
        <p className="fn-disclaim">{config.disclaimer}</p>
      </div>
    </div>
  );
}

Object.assign(window, { FunnelApp, maskValue, fieldValid, fmtSlider });
