/* global React, ReactDOM, jspdf */
// Main app: orchestrates the intro → questions → capture → results flow.
// Posts the captured lead + answers to Formspree, then renders results.
// Also wires the PDF export.

const { useState, useCallback } = React;

const LEAD_ENDPOINT = "/api/lead";

function App() {
  // step: 'intro' | 'questions' | 'followups-loading' | 'followups' | 'capture' | 'results'
  const [step, setStep] = useState('intro');
  const [qIndex, setQIndex] = useState(0);
  const [answers, setAnswers] = useState({}); // { size, goal, maturity, timesink, blocker }
  const [lead, setLead] = useState(null);
  const [enrichment, setEnrichment] = useState(null); // { whyLines, prompt }
  const [enriching, setEnriching] = useState(false);
  const [followups, setFollowups] = useState([]);     // [{ id, title, sub, options }]
  const [followupAnswers, setFollowupAnswers] = useState({}); // { [questionId]: optionId }
  const [followupIndex, setFollowupIndex] = useState(0);

  // ---- Flow handlers ---------------------------------------------------
  const start = () => { setQIndex(0); setAnswers({}); setStep('questions'); window.scrollTo({ top: 0 }); };

  const pick = (value) => {
    const q = QUESTIONS[qIndex];
    setAnswers(a => ({ ...a, [q.id]: value }));
  };

  const next = () => {
    if (qIndex < QUESTIONS.length - 1) {
      setQIndex(i => i + 1);
      window.scrollTo({ top: 0, behavior: 'smooth' });
    } else {
      // Done with the 5 base questions: ask the AI for 2 follow-ups.
      // If it works, render them; if it fails, skip to capture.
      fetchFollowups();
    }
  };

  const fetchFollowups = useCallback(() => {
    setStep('followups-loading');
    window.scrollTo({ top: 0, behavior: 'smooth' });
    const labelled = {
      size:     ANSWER_LABELS.size[answers.size] || "",
      goal:     ANSWER_LABELS.goal[answers.goal] || "",
      maturity: ANSWER_LABELS.maturity[answers.maturity] || "",
      timesink: ANSWER_LABELS.timesink[answers.timesink] || "",
      blocker:  ANSWER_LABELS.blocker[answers.blocker] || "",
    };
    fetch('/api/audit-followups', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ answers: labelled }),
    })
      .then(r => r.ok ? r.json() : null)
      .then(data => {
        if (data && data.ok && Array.isArray(data.questions) && data.questions.length > 0) {
          setFollowups(data.questions);
          setFollowupIndex(0);
          setFollowupAnswers({});
          setStep('followups');
        } else {
          setStep('capture');
        }
      })
      .catch(() => setStep('capture'));
  }, [answers]);

  const pickFollowup = (qid, optid) => {
    setFollowupAnswers(a => ({ ...a, [qid]: optid }));
  };

  const nextFollowup = () => {
    if (followupIndex < followups.length - 1) {
      setFollowupIndex(i => i + 1);
      window.scrollTo({ top: 0, behavior: 'smooth' });
    } else {
      setStep('capture');
      window.scrollTo({ top: 0, behavior: 'smooth' });
    }
  };

  const backFollowup = () => {
    if (followupIndex > 0) {
      setFollowupIndex(i => i - 1);
      window.scrollTo({ top: 0, behavior: 'smooth' });
    } else {
      // Back to last base question
      setStep('questions');
      setQIndex(QUESTIONS.length - 1);
      window.scrollTo({ top: 0, behavior: 'smooth' });
    }
  };

  const skipFollowups = () => {
    setFollowupAnswers({});
    setStep('capture');
    window.scrollTo({ top: 0, behavior: 'smooth' });
  };
  const back = () => {
    if (qIndex > 0) setQIndex(i => i - 1);
    window.scrollTo({ top: 0, behavior: 'smooth' });
  };

  // Resolve follow-up Q&A into human-readable {question, answer} pairs once,
  // so submitLead, the AI personalisation call, the static fallback prompt,
  // and the PDF all see the same data.
  const followupPairs = followups
    .map(q => {
      const optId = followupAnswers[q.id];
      if (!optId) return null;
      const opt = (q.options || []).find(o => o.id === optId);
      if (!opt) return null;
      return { question: q.title, answer: opt.label };
    })
    .filter(Boolean);

  const submitLead = (form) => {
    // Fire-and-forget POST to the Worker so the user sees results immediately.
    // The Worker writes to Notion, validates Turnstile, rejects free email
    // domains. Source tag distinguishes audit vs contact in the CRM.
    const fullName = [form.first, form.last].filter(Boolean).join(' ').trim();

    const payload = {
      source: "AI Marketing Audit",
      name: fullName,
      firstName: form.first,
      lastName: form.last,
      email: form.email,
      industry: form.industry || "",
      industryLabel: (INDUSTRIES.find(i => i.id === form.industry) || {}).label || "",
      turnstileToken: form.turnstileToken || "",
      audit: {
        size:     answers.size || "",
        sizeLabel: ANSWER_LABELS.size[answers.size] || "",
        goal:     ANSWER_LABELS.goal[answers.goal] || "",
        maturity: ANSWER_LABELS.maturity[answers.maturity] || "",
        timesink: ANSWER_LABELS.timesink[answers.timesink] || "",
        blocker:  ANSWER_LABELS.blocker[answers.blocker] || "",
      },
      followups: followupPairs,
    };
    try {
      fetch(LEAD_ENDPOINT, {
        method: "POST",
        headers: { "Accept": "application/json", "Content-Type": "application/json" },
        body: JSON.stringify(payload),
        keepalive: true,
      });
    } catch (_) { /* don't block the flow on a network hiccup */ }

    setLead(form);
    setStep('results');
    window.scrollTo({ top: 0, behavior: 'smooth' });

    // Kick off the AI personalization in parallel. Static output renders
    // immediately; AI version replaces it when the model returns.
    const map = buildOpportunityMap(answers);
    const oppPayload = map.map(({ opp }) => ({
      id: opp.id, title: opp.title, desc: opp.desc, impact: opp.impact, effort: opp.effort,
    }));
    const labelled = {
      size:     ANSWER_LABELS.size[answers.size] || "",
      goal:     ANSWER_LABELS.goal[answers.goal] || "",
      maturity: ANSWER_LABELS.maturity[answers.maturity] || "",
      timesink: ANSWER_LABELS.timesink[answers.timesink] || "",
      blocker:  ANSWER_LABELS.blocker[answers.blocker] || "",
      industry: (INDUSTRIES.find(i => i.id === form.industry) || {}).label || "",
    };
    setEnriching(true);
    fetch('/api/audit-personalize', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ answers: labelled, opportunities: oppPayload, followups: followupPairs }),
    })
      .then(r => r.ok ? r.json() : null)
      .then(data => {
        if (data && data.ok) setEnrichment({ whyLines: data.whyLines, prompt: data.prompt });
      })
      .catch(() => { /* silent fallback to static output */ })
      .finally(() => setEnriching(false));
  };

  const restart = () => {
    setStep('intro'); setQIndex(0); setAnswers({}); setLead(null);
    setEnrichment(null); setEnriching(false);
    setFollowups([]); setFollowupAnswers({}); setFollowupIndex(0);
    window.scrollTo({ top: 0 });
  };
  const backToQuestions = () => {
    // From capture, go back to follow-ups if we have them; otherwise to last base question.
    if (followups.length > 0) {
      setStep('followups');
      setFollowupIndex(followups.length - 1);
    } else {
      setStep('questions');
      setQIndex(QUESTIONS.length - 1);
    }
    window.scrollTo({ top: 0 });
  };
  const bookCall = () => { window.location.href = "/#contact"; };

  // ---- PDF export ------------------------------------------------------
  const download = useCallback(() => {
    if (!window.jspdf) { alert('PDF library not loaded yet. Try again in a moment.'); return; }
    const { jsPDF } = window.jspdf;
    const doc = new jsPDF({ unit: 'pt', format: 'a4' });
    const W = doc.internal.pageSize.getWidth();
    const H = doc.internal.pageSize.getHeight();
    const M = 56; // page margin

    const navy = [5, 60, 94];
    const orange = [255, 135, 0];
    const teal = [20, 91, 91];
    const ink = [42, 42, 42];
    const muted = [95, 95, 95];
    const rule = [200, 197, 192];

    let y = M;

    // Masthead
    doc.setFont('helvetica', 'normal');
    doc.setFontSize(8);
    doc.setTextColor(...navy);
    doc.text('EDUARDO DE LA ESPRIELLA   ·   AI FOR MARKETING · AUDIT', M, y);
    y += 8;
    doc.setDrawColor(...rule);
    doc.setLineWidth(0.5);
    doc.line(M, y, W - M, y);
    y += 36;

    // Title
    doc.setFont('times', 'normal');
    doc.setFontSize(36);
    doc.setTextColor(...navy);
    doc.text('Your AI', M, y); y += 36;
    doc.setFont('times', 'italic');
    doc.setTextColor(...orange);
    doc.text('Opportunity Map.', M, y);
    y += 36;

    // Deck
    doc.setFont('times', 'italic');
    doc.setFontSize(13);
    doc.setTextColor(...ink);
    const deckLines = doc.splitTextToSize('Based on your answers, here are the highest-leverage AI moves for your team right now, sequenced and not stacked.', W - M * 2);
    doc.text(deckLines, M, y);
    y += deckLines.length * 16 + 10;

    // Meta row
    doc.setDrawColor(...rule);
    doc.line(M, y, W - M, y);
    y += 18;
    doc.setFont('helvetica', 'normal');
    doc.setFontSize(7.5);
    doc.setTextColor(...muted);
    const meta = [
      ['PREPARED FOR', `${lead.first}${lead.last ? ' ' + lead.last : ''}`],
      ['TEAM SIZE', ANSWER_LABELS.size[answers.size]],
      ['GOAL', ANSWER_LABELS.goal[answers.goal]],
      ['BIGGEST BLOCKER', ANSWER_LABELS.blocker[answers.blocker]],
    ];
    const colW = (W - M * 2) / meta.length;
    meta.forEach(([k, v], i) => {
      const x = M + colW * i;
      doc.setFont('helvetica', 'normal');
      doc.setTextColor(...muted);
      doc.setFontSize(7.5);
      doc.text(k, x, y);
      doc.setFont('helvetica', 'bold');
      doc.setTextColor(...ink);
      doc.setFontSize(10);
      doc.text(String(v || '·'), x, y + 14);
    });
    y += 34;
    doc.setDrawColor(...rule);
    doc.line(M, y, W - M, y);
    y += 28;

    // Opportunities
    const map = buildOpportunityMap(answers);
    doc.setFont('times', 'normal');
    doc.setFontSize(16);
    doc.setTextColor(...navy);
    doc.text(`${map.length} `, M, y);
    const countW = doc.getTextWidth(`${map.length} `);
    doc.setFont('times', 'italic');
    doc.setTextColor(...orange);
    doc.text('opportunities, in order', M + countW, y);
    y += 20;

    const aiWhyLines = (enrichment && enrichment.whyLines) || {};

    map.forEach(({ opp, why }, i) => {
      if (y > H - 140) { doc.addPage(); y = M; }

      doc.setFont('helvetica', 'normal');
      doc.setFontSize(8);
      doc.setTextColor(...muted);
      doc.text(`NO. ${String(i + 1).padStart(2, '0')}`, M, y);

      doc.setFont('times', 'normal');
      doc.setFontSize(18);
      doc.setTextColor(...navy);
      const titleLines = doc.splitTextToSize(opp.title + '.', W - M * 2 - 70);
      doc.text(titleLines, M + 60, y);
      y += titleLines.length * 20 + 6;

      doc.setFont('helvetica', 'normal');
      doc.setFontSize(10);
      doc.setTextColor(...ink);
      const descLines = doc.splitTextToSize(opp.desc, W - M * 2 - 60);
      doc.text(descLines, M + 60, y);
      y += descLines.length * 13 + 10;

      const renderedWhy = aiWhyLines[opp.id] || why;

      // Badges
      const drawBadge = (x, text, kind) => {
        let fill, textColor, border;
        if (kind === 'high') { fill = orange; textColor = [255, 255, 255]; border = orange; }
        else if (kind === 'med') { fill = null; textColor = teal; border = teal; }
        else { fill = null; textColor = muted; border = rule; }
        doc.setFontSize(7.5);
        doc.setFont('helvetica', 'bold');
        const w = doc.getTextWidth(text) + 14;
        if (fill) { doc.setFillColor(...fill); doc.rect(x, y - 9, w, 14, 'F'); }
        doc.setDrawColor(...border); doc.setLineWidth(0.5); doc.rect(x, y - 9, w, 14, 'S');
        doc.setTextColor(...textColor);
        doc.text(text, x + 7, y);
        return x + w + 6;
      };
      const impactKind = opp.impact === 'High' ? 'high' : (opp.impact === 'Medium' ? 'med' : 'low');
      const effortKind = opp.effort === 'Low' ? 'med' : (opp.effort === 'Medium' ? 'med' : 'low');
      let x = M + 60;
      x = drawBadge(x, `IMPACT · ${opp.impact.toUpperCase()}`, impactKind);
      x = drawBadge(x, `EFFORT · ${opp.effort.toUpperCase()}`, effortKind);
      y += 12;

      // Why box (italic with orange rule)
      doc.setFont('times', 'italic');
      doc.setFontSize(10);
      doc.setTextColor(...ink);
      const whyLines = doc.splitTextToSize('Why this matters for you: ' + renderedWhy, W - M * 2 - 74);
      doc.setDrawColor(...orange); doc.setLineWidth(1.5);
      doc.line(M + 60, y, M + 60, y + whyLines.length * 13);
      doc.text(whyLines, M + 68, y + 10);
      y += whyLines.length * 13 + 24;

      doc.setDrawColor(...rule); doc.setLineWidth(0.5);
      doc.line(M, y, W - M, y);
      y += 22;
    });

    // Prompt + context, fresh page so the user can hand it to print or
    // copy without the opportunity layout fighting for space.
    doc.addPage();
    y = M;

    // Page masthead (consistent with page 1)
    doc.setFont('helvetica', 'normal');
    doc.setFontSize(8);
    doc.setTextColor(...navy);
    doc.text('EDUARDO DE LA ESPRIELLA   ·   AI FOR MARKETING · AUDIT', M, y);
    y += 8;
    doc.setDrawColor(...rule);
    doc.setLineWidth(0.5);
    doc.line(M, y, W - M, y);
    y += 36;

    // Title
    doc.setFont('times', 'normal');
    doc.setFontSize(28);
    doc.setTextColor(...navy);
    doc.text('Take this ', M, y);
    const ttW = doc.getTextWidth('Take this ');
    doc.setFont('times', 'italic');
    doc.setTextColor(...orange);
    doc.text('to your AI.', M + ttW, y);
    y += 24;

    // Deck
    doc.setFont('times', 'italic');
    doc.setFontSize(11.5);
    doc.setTextColor(...muted);
    const promptDeck = doc.splitTextToSize(
      'A prompt and a context template, shaped by your answers. Paste both into Claude, ChatGPT, or whatever you use.',
      W - M * 2
    );
    doc.text(promptDeck, M, y);
    y += promptDeck.length * 14 + 14;

    const renderMonoBlock = (label, body) => {
      // Section label
      doc.setFont('helvetica', 'bold');
      doc.setFontSize(8);
      doc.setTextColor(...navy);
      doc.text(label, M, y);
      y += 12;
      doc.setDrawColor(...orange); doc.setLineWidth(1);
      doc.line(M, y, M + 36, y);
      y += 14;

      // Body in courier (mono) so the structure of the template stays legible
      doc.setFont('courier', 'normal');
      doc.setFontSize(8.5);
      doc.setTextColor(...ink);
      const bodyLines = doc.splitTextToSize(body, W - M * 2);
      for (const line of bodyLines) {
        if (y > H - M - 20) {
          doc.addPage();
          y = M;
          doc.setFont('courier', 'normal');
          doc.setFontSize(8.5);
          doc.setTextColor(...ink);
        }
        doc.text(line, M, y);
        y += 11;
      }
      y += 18;
    };

    const promptText = (enrichment && enrichment.prompt) || buildPrompt(answers, map, followupPairs);
    const contextText = buildContextTemplate();
    renderMonoBlock('01 · PROMPT · copy and paste into your AI', promptText);
    renderMonoBlock('02 · CONTEXT · fill in your details and paste below the prompt', contextText);

    // Final CTA
    if (y > H - 100) { doc.addPage(); y = M; }
    y += 8;
    doc.setFont('times', 'italic');
    doc.setFontSize(14);
    doc.setTextColor(...navy);
    doc.text('Ready for the full audit?', M, y);
    y += 18;
    doc.setFont('helvetica', 'normal');
    doc.setFontSize(10);
    doc.setTextColor(...ink);
    doc.text('Contact me at contact@eddieespriella.com. Two or three clients a quarter.', M, y);

    // Footer
    doc.setFont('helvetica', 'normal');
    doc.setFontSize(7);
    doc.setTextColor(...muted);
    doc.text('© ' + new Date().getFullYear() + ' · EDUARDO DE LA ESPRIELLA · PARIS', M, H - 30);
    doc.text('SET IN TIMES & HELVETICA', W - M, H - 30, { align: 'right' });

    const safeName = `${lead.first}-${lead.last || ''}`.replace(/[^\w-]+/g, '-').replace(/-+$/, '');
    doc.save(`AI-Opportunity-Map-${safeName}.pdf`);
  }, [answers, lead, enrichment, followupPairs]);

  // ---- Render ---------------------------------------------------------
  return (
    <>
      <Masthead />
      {step === 'intro' && <Intro onStart={start} />}
      {step === 'questions' && (
        <QuestionStage
          q={QUESTIONS[qIndex]}
          index={qIndex}
          total={QUESTIONS.length}
          value={answers[QUESTIONS[qIndex].id]}
          onPick={pick}
          onBack={back}
          onNext={next}
        />
      )}
      {step === 'followups-loading' && <FollowupsLoading onSkip={skipFollowups} />}
      {step === 'followups' && followups.length > 0 && (
        <FollowupStage
          q={followups[followupIndex]}
          index={followupIndex}
          total={followups.length}
          value={followupAnswers[followups[followupIndex].id]}
          onPick={pickFollowup}
          onBack={backFollowup}
          onNext={nextFollowup}
          onSkip={skipFollowups}
        />
      )}
      {step === 'capture' && <Capture onSubmit={submitLead} onBack={backToQuestions} />}
      {step === 'results' && <Results answers={answers} lead={lead} onRestart={restart} onDownload={download} onBookCall={bookCall} enrichment={enrichment} enriching={enriching} followupPairs={followupPairs} />}
    </>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);
