/* global React, ReactDOM, Avatar, Scene */
const { useEffect, useRef, useState, useCallback } = React;

const DEFAULT_WORKER_URL = "https://speak-english-proxy.sachindu-dev.workers.dev";

// ---- Scenarios ----
const SCENARIOS = [
  { id: "free",       label: "Free Talk",      icon: "💬", desc: "Chat about anything",   prompt: "The student is having a casual conversation. Be a warm friend chatting about life, hobbies, or whatever the student brings up." },
  { id: "airport",    label: "Airport",        icon: "✈️", desc: "Check-in & boarding",   prompt: "The student is at an airport. Practice check-in, security, asking for directions, boarding — play the airline agent or fellow traveler as needed." },
  { id: "restaurant", label: "Restaurant",     icon: "🍽️", desc: "Ordering food",         prompt: "The student is at a restaurant. Play the server. Practice ordering, asking about the menu, polite requests, paying." },
  { id: "job",        label: "Job Interview",  icon: "💼", desc: "Interview Q & A",       prompt: "The student is in a job interview. Play a friendly hiring manager. Ask common interview questions and react warmly to their answers." },
  { id: "doctor",     label: "Doctor Visit",   icon: "🏥", desc: "Medical English",       prompt: "The student is at a doctor's appointment. Play a warm family doctor. Help the student describe symptoms, ask follow-up questions, suggest next steps." },
  { id: "hotel",      label: "Hotel",          icon: "🏨", desc: "Travel & lodging",      prompt: "The student is checking into a hotel. Play a hotel receptionist. Practice reservations, room requests, check-in." },
  { id: "shopping",   label: "Shopping",       icon: "🛍️", desc: "Shops & returns",       prompt: "The student is shopping. Play a friendly shop assistant. Help the student find items, sizes, prices, returns." },
  { id: "friends",    label: "Making Friends", icon: "👋", desc: "Small talk",            prompt: "The student is meeting new people. Practice introductions, small talk, sharing opinions, and casual social conversation." },
];

const LEVELS = [
  { id: "beginner",           label: "Beginner",     desc: "Simple words, slow pace"  },
  { id: "elementary",         label: "Elementary",   desc: "Basic grammar, common phrases" },
  { id: "intermediate",       label: "Intermediate", desc: "Natural conversation flow" },
  { id: "upper-intermediate", label: "Upper-Int.",   desc: "Idioms, complex grammar" },
  { id: "advanced",           label: "Advanced",     desc: "Near-native, subtle errors" },
];

const DEMO_USER_LINES = {
  free:       ["I want telling you about my weekend.", "Yesterday I go to the park with my friends.", "It was very fun, we drink coffee and talk many things."],
  airport:    ["Hello, I want check in for the flight to London please.", "I have one bag for going in plane.", "What time the boarding will start?"],
  restaurant: ["Hi, can I see the menu please?", "I want order the pasta but no with cheese.", "Can you bring me the bill, please?"],
  job:        ["Hello, nice to meeting you.", "I have five years experience in marketing.", "I am liking to work with teams."],
  doctor:     ["Hello doctor, I am not feeling good today.", "My head is paining since two days.", "Should I taking some medicine?"],
  hotel:      ["Hello, I have a reservation for two night.", "Can I get a room with view to the sea?", "Can I have more towel please?"],
  shopping:   ["Excuse me, do you have this shirt in big size?", "How much it is costing?", "Can I to pay with card?"],
  friends:    ["Hi, my name is Sam, nice to meet with you.", "I am living in this city since three year.", "What hobbies you are doing in weekend?"],
};

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "showCaptions": true,
  "agentVoice": true,
  "demoAutoplay": false
}/*EDITMODE-END*/;

const SETTINGS_KEY = "speak-english-settings-v2";
const HISTORY_KEY  = "speak-english-history-v2";

function loadSettings() {
  try { return JSON.parse(localStorage.getItem(SETTINGS_KEY)) || {}; }
  catch { return {}; }
}
function saveSettings(s) { localStorage.setItem(SETTINGS_KEY, JSON.stringify(s)); }

function loadHistory() {
  try { return JSON.parse(sessionStorage.getItem(HISTORY_KEY)) || []; }
  catch { return []; }
}
function saveHistory(h) { sessionStorage.setItem(HISTORY_KEY, JSON.stringify(h)); }

// ---- Caption text renderer ----
function CaptionText({ segments, typingTo }) {
  if (typingTo != null) {
    return (
      <span>
        {typingTo}
        <span className="typing-cursor" />
      </span>
    );
  }
  return (
    <span>
      {(segments || []).map((seg, i) =>
        seg.kind === "fix" ? (
          <span key={i} className="fix" title="Correction">
            {seg.was && <span className="fix-was">{seg.was}</span>}
            {seg.text}
          </span>
        ) : (
          <span key={i}>{seg.text}</span>
        )
      )}
    </span>
  );
}

// ---- Main App ----
function App() {
  const [tweaks, setTweak] = (window.useTweaks
    ? window.useTweaks(TWEAK_DEFAULTS)
    : useFallbackTweaks(TWEAK_DEFAULTS)
  );

  const initialSettings = loadSettings();
  const [scenarioId, setScenarioId] = useState(initialSettings.scenarioId || "free");
  const [level, setLevel]           = useState(initialSettings.level || "intermediate");
  const [history, setHistory]       = useState(loadHistory());

  const [state, setState]         = useState("idle");
  const [mood, setMood]           = useState("neutral");
  const [amp, setAmp]             = useState(0);
  const [caption, setCaption]     = useState(null);
  const [suggestions, setSuggestions] = useState([]);
  const [showDrawer, setShowDrawer]   = useState(false);
  const [showSheet, setShowSheet]     = useState(false);
  const [pendingScenario, setPendingScenario] = useState(scenarioId);
  const [pendingLevel, setPendingLevel]       = useState(level);
  const [hintText, setHintText]   = useState("Tap to speak. Mira will respond.");
  const ampRafRef  = useRef();
  const demoIndexRef = useRef(0);

  const scenario = SCENARIOS.find(s => s.id === scenarioId) || SCENARIOS[0];

  useEffect(() => { saveSettings({ scenarioId, level }); }, [scenarioId, level]);
  useEffect(() => { saveHistory(history); }, [history]);

  useEffect(() => {
    if (history.length === 0 && !caption) {
      const greeting = makeGreeting(scenario, level);
      typeAgentMessage(greeting);
    }
    // eslint-disable-next-line
  }, [scenarioId]);

  // Mouth amplitude animation while speaking
  useEffect(() => {
    if (state !== "speaking") { setAmp(0); return; }
    let t0 = performance.now();
    const tick = (t) => {
      const dt = (t - t0) / 1000;
      const n =
        Math.abs(Math.sin(dt * 9.5))  * 0.5 +
        Math.abs(Math.sin(dt * 17.3)) * 0.3 +
        Math.abs(Math.sin(dt * 5.1))  * 0.2;
      setAmp(Math.max(0.05, Math.min(1, n)));
      ampRafRef.current = requestAnimationFrame(tick);
    };
    ampRafRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(ampRafRef.current);
  }, [state]);

  // TTS
  const speakText = useCallback((text) => {
    if (!tweaks.agentVoice) return;
    if (!("speechSynthesis" in window)) return;
    try {
      speechSynthesis.cancel();
      const u = new SpeechSynthesisUtterance(stripTags(text));
      u.lang = "en-US";
      u.rate = 1.0;
      u.pitch = 1.05;
      speechSynthesis.speak(u);
    } catch {}
  }, [tweaks.agentVoice]);

  // Typewriter reveal of agent message
  const typeAgentMessage = useCallback((messageObj) => {
    const fullText = renderSegmentsToText(messageObj.segments);
    setSuggestions([]);
    setMood(messageObj.mood || "encouraging");
    setState("speaking");
    speakText(fullText);

    let i = 0;
    setCaption({ who: "mira", segments: [], typingTo: "" });
    const step = () => {
      i += Math.max(1, Math.round(fullText.length / 80));
      const slice = fullText.slice(0, i);
      setCaption({ who: "mira", segments: [], typingTo: slice });
      if (i < fullText.length) {
        setTimeout(step, 22);
      } else {
        setCaption({ who: "mira", segments: messageObj.segments });
        setHistory(h => [...h, { role: "mira", segments: messageObj.segments, raw: fullText }]);
        setSuggestions(messageObj.suggestions || []);
        setTimeout(() => {
          setState("idle");
          setMood("neutral");
          setHintText("Tap to speak when ready.");
        }, Math.min(2200, fullText.length * 50));
      }
    };
    setTimeout(step, 200);
  }, [speakText]);

  // ---- Handle user utterance ----
  const handleUserUtterance = useCallback(async (userText) => {
    setSuggestions([]);
    setCaption({ who: "user", segments: [{ kind: "text", text: userText }] });
    setHistory(h => [...h, { role: "user", segments: [{ kind: "text", text: userText }], raw: userText }]);
    setState("thinking");
    setMood("thinking");
    setHintText("Mira is thinking…");

    let agentMsg;
    try {
      agentMsg = await callWorker(userText, scenario, level, history);
    } catch (err) {
      console.warn("Worker error:", err);
      agentMsg = mockReply(userText, scenario, level);
    }
    typeAgentMessage(agentMsg);
  }, [scenario, level, history, typeAgentMessage]);

  // ---- Web Speech recognition ----
  const recRef = useRef(null);
  const startListening = useCallback(async () => {
    const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
    const inIframe = window.self !== window.top;
    if (!SR || inIframe) {
      setState("listening");
      setMood("encouraging");
      setHintText("Listening… (demo mode)");
      const lines = DEMO_USER_LINES[scenarioId] || DEMO_USER_LINES.free;
      const next = lines[demoIndexRef.current % lines.length];
      demoIndexRef.current += 1;
      setTimeout(() => { setState("idle"); handleUserUtterance(next); }, 1800);
      return;
    }
    if (!recRef.current) {
      const r = new SR();
      r.lang = "en-US";
      r.interimResults = true;
      r.continuous = false;
      r.onstart = () => { setState("listening"); setMood("encouraging"); setHintText("I'm listening…"); };
      r.onresult = (e) => {
        let finalText = "";
        for (let i = e.resultIndex; i < e.results.length; i++) {
          if (e.results[i].isFinal) finalText += e.results[i][0].transcript;
        }
        if (finalText.trim()) handleUserUtterance(finalText.trim());
      };
      r.onend = () => { if (state === "listening") setState("idle"); };
      r.onerror = (e) => {
        setState("idle");
        if (e.error === "not-allowed" || e.error === "service-not-allowed") {
          setHintText("Microphone blocked. Check browser permissions.");
        } else {
          setHintText("Couldn't hear you — try again.");
        }
      };
      recRef.current = r;
    }
    try { recRef.current.start(); } catch {}
  }, [scenarioId, state, handleUserUtterance]);

  const stopListening = useCallback(() => {
    try { recRef.current?.stop(); } catch {}
    setState("idle");
  }, []);

  const onMicClick = () => {
    if (state === "listening") stopListening();
    else if (state === "idle") startListening();
  };

  const onPickScenario = () => {
    setPendingScenario(scenarioId);
    setPendingLevel(level);
    setShowSheet(true);
  };

  const onApplyScenario = () => {
    const changed = pendingScenario !== scenarioId;
    setScenarioId(pendingScenario);
    setLevel(pendingLevel);
    setShowSheet(false);
    if (changed) {
      setHistory([]);
      setCaption(null);
      demoIndexRef.current = 0;
      setTimeout(() => {
        const sc = SCENARIOS.find(s => s.id === pendingScenario);
        typeAgentMessage(makeGreeting(sc, pendingLevel));
      }, 200);
    }
  };

  const onClear = () => {
    setHistory([]);
    setCaption(null);
    demoIndexRef.current = 0;
    setTimeout(() => typeAgentMessage(makeGreeting(scenario, level)), 200);
  };

  // ---- Render ----
  return (
    <div className="stage">
      <Scene scenarioId={scenarioId} />

      {/* Top bar */}
      <div className="topbar">
        <div className="brand">
          <div className="brand-mark">M</div>
          <div>
            <div className="brand-name">Mira</div>
            <div className="brand-sub">English coach</div>
          </div>
        </div>

        <button className="scenario-pill" onClick={onPickScenario} title="Change lesson">
          <span className="dot" style={{ background: "var(--cream-2)" }}>{scenario.icon}</span>
          <span>{scenario.label}</span>
          <span style={{ color: "var(--ink-3)", fontSize: 11, marginLeft: 4 }}>· {levelShort(level)}</span>
          <svg className="chev" viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2"><path d="M4 6l4 4 4-4" /></svg>
        </button>

        <div className="top-actions">
          <button className="icon-btn" onClick={() => setShowDrawer(true)} title="Conversation history" aria-label="History">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z" strokeLinecap="round" strokeLinejoin="round" /></svg>
          </button>
        </div>
      </div>

      {/* Avatar */}
      <div className="avatar-wrap">
        <div className={`avatar-ring ${state === "listening" ? "listening" : ""}`}>
          <div className="pulse" />
          <div className="pulse p2" />
          <div className="pulse p3" />
          <Avatar state={state} mood={mood} speakingAmp={amp} />
        </div>
        <div className="avatar-name">
          Mira
          <span className="live-dot" />
        </div>
        <div className="avatar-status">{statusLabel(state, scenario)}</div>
      </div>

      {/* Caption card */}
      {tweaks.showCaptions && caption && (
        <div className="caption-area">
          <div className="caption-card" key={(caption.typingTo ?? "") + (caption.segments?.length || 0)}>
            <div className={`caption-label ${caption.who}`}>
              {caption.who === "mira" ? "MIRA" : "YOU SAID"}
              {caption.who === "mira" && state === "speaking" && (
                <span style={{ marginLeft: 6, opacity: 0.6 }}>· speaking</span>
              )}
            </div>
            <div className="caption-text">
              <CaptionText segments={caption.segments || []} typingTo={caption.typingTo} />
            </div>

            {caption.who === "mira" && state !== "speaking" && hasFixes(caption.segments) && (
              <div className="caption-actions">
                <button className="chip" onClick={() => speakText(renderSegmentsToText(caption.segments))}>
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3 12h4l5-5v10l-5-5H3z" strokeLinecap="round" strokeLinejoin="round"/><path d="M16 9a3 3 0 0 1 0 6" strokeLinecap="round"/></svg>
                  Hear again
                </button>
              </div>
            )}
          </div>
        </div>
      )}

      {/* Suggestion chips */}
      {suggestions.length > 0 && state === "idle" && (
        <div className="suggest-row">
          {suggestions.map((s, i) => (
            <button key={i} className="chip suggested" onClick={() => handleUserUtterance(s)}>
              {s}
            </button>
          ))}
        </div>
      )}

      {/* Controls */}
      <div className="controls">
        <div className="control-side">
          <button className="tool-btn" onClick={onClear} title="Start over">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3 12a9 9 0 1 0 3-6.7L3 8" strokeLinecap="round" strokeLinejoin="round"/><path d="M3 3v5h5" strokeLinecap="round" strokeLinejoin="round"/></svg>
          </button>
        </div>

        <button
          className={`mic-btn ${state === "listening" ? "listening" : ""} ${state === "thinking" ? "thinking" : ""}`}
          onClick={onMicClick}
          disabled={state === "thinking" || state === "speaking"}
          aria-label={state === "listening" ? "Stop" : "Tap to speak"}
        >
          {state === "listening" ? (
            <div className="waveform">
              {Array.from({ length: 9 }).map((_, i) => <div key={i} className="bar" />)}
            </div>
          ) : (
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <rect x="9" y="2" width="6" height="12" rx="3" fill="currentColor" stroke="none" />
              <path d="M5 11a7 7 0 0 0 14 0" strokeLinecap="round" />
              <path d="M12 18v4" strokeLinecap="round" />
              <path d="M8 22h8" strokeLinecap="round" />
            </svg>
          )}
          <div className="mic-label">{micLabel(state)}</div>
        </button>

        <div className="control-side">
          <button
            className={`tool-btn ${tweaks.agentVoice ? "active" : ""}`}
            onClick={() => setTweak('agentVoice', !tweaks.agentVoice)}
            title={tweaks.agentVoice ? "Mute Mira's voice" : "Unmute"}
          >
            {tweaks.agentVoice ? (
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M11 5L6 9H2v6h4l5 4V5z" strokeLinejoin="round" /><path d="M15 9a3 3 0 0 1 0 6" strokeLinecap="round"/><path d="M18 6a7 7 0 0 1 0 12" strokeLinecap="round"/></svg>
            ) : (
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M11 5L6 9H2v6h4l5 4V5z" strokeLinejoin="round" /><path d="M22 9l-6 6M16 9l6 6" strokeLinecap="round"/></svg>
            )}
          </button>
        </div>
      </div>

      {/* History drawer */}
      <div className={`drawer-backdrop ${showDrawer ? "open" : ""}`} onClick={() => setShowDrawer(false)} />
      <aside className={`drawer ${showDrawer ? "open" : ""}`}>
        <div className="drawer-head">
          <div className="drawer-title">Conversation</div>
          <button className="icon-btn" onClick={() => setShowDrawer(false)} aria-label="Close">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M6 6l12 12M18 6L6 18" strokeLinecap="round" /></svg>
          </button>
        </div>
        <div className="drawer-body">
          {history.length === 0 && (
            <div className="drawer-empty">Your conversation will appear here.</div>
          )}
          {history.map((turn, i) => (
            <div className="history-turn" key={i}>
              <div className={`history-meta ${turn.role}`}>
                {turn.role === "mira" ? "MIRA" : "YOU"}
              </div>
              <div className="history-text">
                <CaptionText segments={turn.segments} />
              </div>
            </div>
          ))}
        </div>
      </aside>

      {/* Tweaks panel (dev tool) */}
      {window.TweaksPanel && (
        <window.TweaksPanel title="Tweaks">
          <window.TweakSection label="Display" />
          <window.TweakToggle
            label="Mira speaks out loud"
            value={tweaks.agentVoice}
            onChange={(v) => setTweak('agentVoice', v)}
          />
          <window.TweakToggle
            label="Show captions"
            value={tweaks.showCaptions}
            onChange={(v) => setTweak('showCaptions', v)}
          />
          <window.TweakSection label="Try it" />
          <window.TweakButton
            label="Send a sample line"
            onClick={() => {
              const lines = DEMO_USER_LINES[scenarioId] || DEMO_USER_LINES.free;
              const next = lines[demoIndexRef.current % lines.length];
              demoIndexRef.current += 1;
              handleUserUtterance(next);
            }}
          />
          <window.TweakButton label="Start over" onClick={onClear} />
        </window.TweaksPanel>
      )}

      {/* Scenario / lesson sheet */}
      <div className={`sheet ${showSheet ? "open" : ""}`}>
        <div className="sheet-backdrop" onClick={() => setShowSheet(false)} />
        <div className="sheet-panel">
          <div className="sheet-grabber" />
          <h2 className="display">Pick a lesson</h2>
          <p className="sub">Where would you like to practice today?</p>

          <p style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: "0.1em", color: "var(--ink-3)", margin: "0 0 8px", fontWeight: 600 }}>Your level</p>
          <div className="level-row">
            {LEVELS.map(lv => (
              <button
                key={lv.id}
                className={`level-chip ${pendingLevel === lv.id ? "active" : ""}`}
                onClick={() => setPendingLevel(lv.id)}
              >
                {lv.label}
              </button>
            ))}
          </div>

          <p style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: "0.1em", color: "var(--ink-3)", margin: "0 0 8px", fontWeight: 600 }}>Scenario</p>
          <div className="scenario-grid">
            {SCENARIOS.map(sc => (
              <button
                key={sc.id}
                className={`scenario-card ${pendingScenario === sc.id ? "selected" : ""}`}
                onClick={() => setPendingScenario(sc.id)}
              >
                <div className="sc-emoji">{sc.icon}</div>
                <div className="sc-label">{sc.label}</div>
                <div className="sc-desc">{sc.desc}</div>
              </button>
            ))}
          </div>

          <button className="sheet-cta" onClick={onApplyScenario}>
            Start lesson →
          </button>
        </div>
      </div>
    </div>
  );
}

// ---- Worker integration ----
async function callWorker(userText, scenario, level, history) {
  const res = await fetch(DEFAULT_WORKER_URL.replace(/\/$/, ""), {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      utterance: userText,
      level,
      scenario: scenario.prompt || "",
      history: history.slice(-8).map(t => ({
        role: t.role === "mira" ? "ai" : "user",
        text: t.raw,
      })),
    }),
  });

  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(err.error || "Worker error " + res.status);
  }

  const data = await res.json();
  const segments = [];

  if (data.hasErrors && data.mistakes && data.mistakes.length > 0) {
    const fix = data.mistakes[0];
    segments.push({ kind: "text", text: "Got it! We usually say " });
    segments.push({ kind: "fix", was: fix.original, text: fix.correction });
    segments.push({ kind: "text", text: ". " + (data.reply || "") });
  } else {
    segments.push({ kind: "text", text: data.reply || "" });
  }

  return {
    segments,
    mood: data.hasErrors ? "encouraging" : "delighted",
    suggestions: contextualSuggestions(scenario.id),
  };
}

// ---- Mock reply (offline fallback) ----
function mockReply(userText, scenario, level) {
  const fixes = detectSimpleFixes(userText);
  const segments = [];
  const replies = friendlyReplies(scenario.id);
  const opener = replies[Math.floor(Math.random() * replies.length)];

  if (fixes.length === 0) {
    segments.push({ kind: "text", text: opener + " " + contextualFollowUp(scenario.id) });
    return { segments, mood: "delighted", suggestions: contextualSuggestions(scenario.id) };
  }

  const fix = fixes[0];
  segments.push({ kind: "text", text: "Got it! We usually say " });
  segments.push({ kind: "fix", was: fix.was, text: fix.fix });
  segments.push({ kind: "text", text: ". " + opener + " " + contextualFollowUp(scenario.id) });
  return { segments, mood: "encouraging", suggestions: contextualSuggestions(scenario.id) };
}

function detectSimpleFixes(text) {
  const lower = " " + text.toLowerCase().replace(/[.,?!]/g, "") + " ";
  const fixes = [];
  const patterns = [
    [/ i go to /,             "go to",              "went to"],
    [/ i want telling /,      "want telling",       "want to tell"],
    [/ i want check /,        "want check",         "would like to check"],
    [/ i want order /,        "want order",         "would like to order"],
    [/ i am liking /,         "am liking",          "like"],
    [/ how much it is /,      "how much it is",     "how much is it"],
    [/ how much is cost /,    "how much is cost",   "how much does it cost"],
    [/ i am not feeling good /,"feeling good",      "feeling well"],
    [/ my head is paining /,  "head is paining",    "head hurts"],
    [/ since two days /,      "since two days",     "for two days"],
    [/ since three year /,    "since three year",   "for three years"],
    [/ for going in plane /,  "for going in plane", "to take on the plane"],
    [/ what time the boarding /,"what time the boarding","what time does boarding"],
    [/ for my fly /,          "fly",                "flight"],
    [/ no with cheese /,      "no with cheese",     "without cheese"],
    [/ two night /,           "two night",          "two nights"],
    [/ big size /,            "big size",           "a large size"],
    [/ i to pay /,            "I to pay",           "I pay"],
    [/ nice to meeting /,     "nice to meeting",    "nice to meet"],
    [/ have catch /,          "have catch",         "have caught"],
    [/ should i taking /,     "should I taking",    "should I take"],
    [/ i'm think /,           "I'm think",          "I think"],
    [/ five years experience /,"five years experience","five years of experience"],
  ];
  for (const [rx, was, fix] of patterns) {
    if (rx.test(lower)) fixes.push({ was, fix });
  }
  return fixes;
}

function friendlyReplies(id) {
  return ({
    free:       ["That sounds nice!", "Oh I love hearing that.", "Tell me more!"],
    airport:    ["No problem.", "Sure thing.", "Of course."],
    restaurant: ["Coming right up!", "Excellent choice!", "Wonderful."],
    job:        ["Great — thanks for sharing.", "That's helpful to know.", "I appreciate that."],
    doctor:     ["I'm sorry to hear that.", "Okay, let's see.", "Thanks for telling me."],
    hotel:      ["Of course.", "Absolutely.", "Let me check that for you."],
    shopping:   ["Let me check for you.", "Sure!", "We do."],
    friends:    ["Nice to meet you!", "Oh cool!", "That's awesome."],
  })[id] || ["Got it.", "Okay!"];
}

function contextualFollowUp(id) {
  return ({
    free:       "What did you do over the weekend?",
    airport:    "May I see your passport, please?",
    restaurant: "Would you like still or sparkling water to start?",
    job:        "What attracted you to this role?",
    doctor:     "How long has this been going on?",
    hotel:      "Could I have your name and a card on file?",
    shopping:   "Would you like to try it on?",
    friends:    "So what brings you here?",
  })[id] || "Tell me more.";
}

function contextualSuggestions(id) {
  return ({
    free:       ["I watched a movie", "I worked all weekend"],
    airport:    ["Here's my passport", "I have one carry-on"],
    restaurant: ["Sparkling, please", "Still water, thanks"],
    job:        ["The mission interests me", "I love this industry"],
    doctor:     ["About two days", "Since yesterday"],
    hotel:      ["Sam Carter, here's my card", "I booked online"],
    shopping:   ["Yes, please", "Maybe later"],
    friends:    ["I just moved here", "I'm visiting a friend"],
  })[id] || [];
}

function makeGreeting(scenario, level) {
  const lines = {
    free:       "Hi! Lovely to see you again — what's on your mind today?",
    airport:    "Welcome to Terminal 3! ✈️ Are you checking in for a flight today?",
    restaurant: "Welcome in! 🍽️ A table for one, or are you joining someone?",
    job:        "Hello! Thanks for coming in. Please, have a seat. 💼 Tell me a little about yourself.",
    doctor:     "Hi there. Take your time — what brings you in today? 🏥",
    hotel:      "Welcome to the Grand! 🏨 Do you have a reservation with us?",
    shopping:   "Hi! Welcome in. 🛍️ Anything I can help you find today?",
    friends:    "Oh, hey! 👋 I don't think we've met — I'm Mira. What's your name?",
  }[scenario.id] || "Hi! I'm Mira. Tap the mic and we'll get started.";

  return {
    segments: [{ kind: "text", text: lines }],
    mood: "encouraging",
    suggestions: starterSuggestions(scenario.id),
  };
}

function starterSuggestions(id) {
  return ({
    free:       ["Tell me about your weekend", "Ask me something"],
    airport:    ["I'd like to check in", "Where is the gate?"],
    restaurant: ["Can I see the menu?", "What do you recommend?"],
    job:        ["Tell me about yourself", "I have five years of experience"],
    doctor:     ["I have a headache", "I haven't been sleeping well"],
    hotel:      ["I have a reservation", "Do you have a room with a view?"],
    shopping:   ["Do you have this in another size?", "How much is it?"],
    friends:    ["Hi, I'm Sam!", "Where are you from?"],
  })[id] || [];
}

// ---- Helpers ----
function levelShort(l) {
  return ({ beginner: "Beginner", elementary: "Elementary", intermediate: "Intermediate", "upper-intermediate": "Upper-Int.", advanced: "Advanced" })[l] || l;
}

function statusLabel(state, scenario) {
  if (state === "listening") return `Listening · ${scenario.label}`;
  if (state === "thinking")  return "Thinking…";
  if (state === "speaking")  return "Speaking…";
  return `Ready · ${scenario.label}`;
}

function micLabel(state) {
  if (state === "listening") return "Listening";
  if (state === "thinking")  return "Thinking";
  if (state === "speaking")  return "Mira speaking";
  return "Tap to speak";
}

function stripTags(t) { return t.replace(/<[^>]+>/g, ""); }

function renderSegmentsToText(segs) {
  return (segs || []).map(s => s.text).join("");
}

function hasFixes(segs) {
  return segs?.some(s => s.kind === "fix");
}

function useFallbackTweaks(defaults) {
  const [vals, setVals] = useState(defaults);
  const setter = (k, v) => {
    if (typeof k === "object") setVals(prev => ({ ...prev, ...k }));
    else setVals(prev => ({ ...prev, [k]: v }));
  };
  return [vals, setter];
}

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