// ============================================================
// APP — AI chat interface that renders portfolio as widgets
// ============================================================
const { useState, useEffect, useRef, useMemo } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": localStorage.getItem("theme") || "light",
  "accent": "#c03010"
} /*EDITMODE-END*/;

// ----- Projects data -----
const PROJECTS = {
  "Don't Look Away": {
    title: "Don't Look Away",
    tag: "PASSION · VR",
    year: "'23",
    icon: "moon",
    bg: "#151414",
    fg: "#e8e5de",
    desc: "A VR survival horror game. Enemies freeze only while you look at them — glance away and they advance.",
    href: "case-studies/dont-look-away.html"
  },
  "ESUS Calc": {
    title: "ESUS Calculator",
    tag: "PASSION · TOOL",
    year: "'23",
    icon: "bolt",
    bg: "#f2efe8",
    fg: "#0f0f0f",
    desc: "A UX research calculator for a lazy, stubborn UX designer. Tallies ESUS scores, copy-pastes to Notion.",
    href: "case-studies/esus-calc.html"
  },
  "Chalan Che'lu": {
    title: "Chalan Che'lu Mart",
    tag: "PASSION · GAME",
    year: "'22",
    icon: "star",
    bg: "#c03010",
    fg: "#fef9e8",
    desc: "A top-down mini-market game set on Guam, built with pixel art and an open-source engine.",
    href: "case-studies/chalan-chelu.html"
  },
  "Design System": {
    title: "Enterprise Design System",
    tag: "DISNEY · EDL/EDS",
    year: "'24",
    icon: "figma",
    bg: "#1a1a28",
    fg: "#e8e5de",
    desc: "Figma-based design system powering experiences across Disney's media supply chain.",
    href: "case-studies/design-system.html"
  },
  "Media Tagging": {
    title: "Media Metadata Tagging",
    tag: "DISNEY · ENTERPRISE",
    year: "'23",
    icon: "play",
    bg: "#0f1e14",
    fg: "#e8e5de",
    desc: "An enterprise tool to tag, annotate, and prep media for distribution across proprietary streaming platforms.",
    href: "case-studies/media-tagging.html"
  }
};

// ----- Prompt responses -----
const PROMPT_LIBRARY = [
{
  id: "intro",
  match: ["who are", "who's", "hello", "introduce"],
  prompt: "Who are you?",
  thinking: ["Warming up…", "Pulling bio…"],
  reply: ({ time }) =>
  <>
        <Reply>
          Hi, I'm <em style={{ fontFamily: "var(--serif)", fontSize: "1.15em" }}>Lianna Lamorena</em> — a UX & Product Designer with <strong>9 years</strong> designing enterprise, finance, and entertainment software. I'm currently open to senior / staff / design-lead roles.
        </Reply>
        <Grid cols={2}>
          <HoursWidget timeStr={time} />
          <IntroWidget />
        </Grid>
        <div style={{ fontSize: 12, color: "var(--muted)", fontFamily: "var(--mono)", marginTop: 4 }}>
          Chat with <strong style={{ color: "var(--ink)" }}>MINI-LI</strong> below to ask anything about me and my work.
        </div>
      </>

},
{
  id: "work",
  match: ["work", "projects", "portfolio", "case", "shown", "built"],
  prompt: "Show me your work",
  thinking: ["Sorting by recency…", "Loading case studies…"],
  reply: () =>
  <>
        <Reply>Here's a timeline of everything I've shipped and made for fun. The top row is a compressed view; full case studies below.</Reply>
        <NowWidget />
        <WeekWidget />
        <Grid cols={1} gap={14}>
          <ProjectCard project={PROJECTS["Design System"]} />
          <Grid cols={2} gap={14}>
            <ProjectCard project={PROJECTS["Media Tagging"]} />
            <ProjectCard project={PROJECTS["Don't Look Away"]} />
          </Grid>
          <Grid cols={2} gap={14}>
            <ProjectCard project={PROJECTS["ESUS Calc"]} />
            <ProjectCard project={PROJECTS["Chalan Che'lu"]} />
          </Grid>
        </Grid>
      </>

},
{
  id: "experience",
  match: ["résumé", "resume", "cv", "work history", "career history", "companies", "where have you worked"],
  prompt: "What's your experience?",
  thinking: ["Parsing résumé…", "9 years · compiling…"],
  reply: () =>
  <>
        <Reply>Nine years across enterprise design — currently at Disney leading AI adoption and evolving the Enterprise Design Language. Previously led UX for developer experience & cloud infra at American Express.</Reply>
        <ResumeWidget />
        <Grid cols={3}>
          <ExperienceWidget />
          <AvailabilityWidget />
          <NowPlayingWidget />
        </Grid>
      </>

},
{
  id: "stack",
  match: ["stack", "expertise", "skills"],
  prompt: "What's your expertise?",
  thinking: ["Sifting domains…"],
  reply: () =>
  <>
        <Reply>Nine years means I've gone deep in a lot of rooms. Here's the menu:</Reply>
        <SkillsWidget />
        <Grid cols={2}>
          <NowPlayingWidget />
          <AvailabilityWidget />
        </Grid>
      </>

},
{
  id: "contact",
  match: ["contact", "hire", "email", "reach", "message", "in touch", "work together"],
  prompt: "How do I reach you?",
  thinking: ["Opening channels…"],
  reply: ({ time }) =>
  <>
        <Reply>Easiest is email — I usually reply within a day. I'm in <strong>Seattle (PST)</strong>, currently {time}.</Reply>
        <ContactWidget />
        <Grid cols={2}>
          <ResponseWidget />
          <LocationWidget tz={time} />
        </Grid>
      </>

}];


// ----- Building blocks -----
function Reply({ children }) {
  return (
    <div style={{
      fontSize: 14, lineHeight: 1.6,
      color: "var(--ink)",
      padding: "4px 6px 10px",
      fontFamily: "var(--mono)"
    }}>{children}</div>);

}

function AIReply({ text }) {
  return (
    <div style={{
      fontSize: 14, lineHeight: 1.6,
      color: "var(--ink)",
      padding: "4px 6px 10px",
      fontFamily: "var(--mono)"
    }}>{text}</div>);
}

function Grid({ cols = 2, gap = 12, children }) {
  return (
    <div className="r-grid" style={{
      "--grid-cols": cols,
      display: "grid",
      gridTemplateColumns: "repeat(var(--grid-cols), 1fr)",
      gap
    }}>{children}</div>);

}

// ----- Thinking scribble -----
function Thinking({ label }) {
  return (
    <div style={{
      display: "flex", alignItems: "center", gap: 10,
      fontSize: 12, color: "var(--muted)",
      fontFamily: "var(--mono)",
      padding: "10px 14px",
      background: "var(--card)",
      borderRadius: 14,
      width: "fit-content"
    }}>
      <svg width="36" height="20" viewBox="0 0 36 20" fill="none" style={{ flexShrink: 0 }}>
        <path
          d="M2 14 C4 6, 7 4, 9 10 C11 16, 13 4, 16 8 C18 11, 19 6, 21 10 C23 14, 25 4, 28 9 C30 12, 32 8, 34 10"
          stroke="var(--accent)"
          strokeWidth="1.8"
          strokeLinecap="round"
          strokeLinejoin="round"
          fill="none"
          strokeDasharray="80"
          strokeDashoffset="80"
          style={{ animation: "scribble 1.1s ease-in-out infinite" }}
        />
      </svg>
      <span>{label}</span>
      <style>{`
        @keyframes scribble {
          0%   { stroke-dashoffset: 80; opacity: 1; }
          70%  { stroke-dashoffset: 0;  opacity: 1; }
          85%  { stroke-dashoffset: 0;  opacity: 0; }
          100% { stroke-dashoffset: 80; opacity: 0; }
        }
      `}</style>
    </div>);
}

// ----- User prompt bubble -----
function UserBubble({ text }) {
  return (
    <div style={{ display: "flex", justifyContent: "flex-end", marginBottom: 14 }}>
      <div style={{
        background: "var(--ink)",
        color: "var(--bg)",
        borderRadius: 20,
        padding: "10px 16px",
        fontSize: 13,
        fontFamily: "var(--mono)",
        maxWidth: "70%"
      }}>{text}</div>
    </div>);

}

// ----- Header -----
function Header({ time, theme, onToggleTheme }) {
  return (
    <header style={{
      display: "flex", alignItems: "center", justifyContent: "space-between",
      padding: "20px 28px",
      position: "sticky", top: 0,
      background: "color-mix(in oklab, var(--bg) 90%, transparent)",
      backdropFilter: "blur(12px)",
      WebkitBackdropFilter: "blur(12px)",
      zIndex: 10,
      borderBottom: "1px solid var(--rule)"
    }}>
      <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
        <div style={{
          width: 28, height: 28, borderRadius: "50%",
          background: "var(--accent)",
          display: "grid", placeItems: "center",
          color: "#fff", fontFamily: "var(--serif)", fontSize: 18, fontStyle: "italic", lineHeight: 1
        }}>L</div>
        <div style={{ fontWeight: 700, letterSpacing: ".02em", fontSize: 13 }}>Lianna Lamorena</div>
        <div style={{ fontSize: 11, color: "var(--muted)", marginLeft: 6 }}>· UX/Product</div>
      </div>
      <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 11, color: "var(--muted)" }}>
          <PixelIcon name="clock" size={11} color="var(--muted)" />
          {time} PST
        </div>
        <a href="/work.html" style={{
          display: "flex", alignItems: "center", gap: 6,
          fontSize: 11, color: "var(--muted)", textDecoration: "none",
          padding: "4px 10px", borderRadius: 999,
          border: "1px solid var(--rule)",
          fontFamily: "var(--mono)", letterSpacing: ".06em", fontWeight: 600
        }}
        onMouseEnter={(e) => { e.currentTarget.style.color = "var(--ink)"; e.currentTarget.style.borderColor = "var(--ink)"; }}
        onMouseLeave={(e) => { e.currentTarget.style.color = "var(--muted)"; e.currentTarget.style.borderColor = "var(--rule)"; }}>
          CASE STUDIES
        </a>
        <a href="/resume.html" style={{
          display: "flex", alignItems: "center", gap: 6,
          fontSize: 11, color: "var(--muted)", textDecoration: "none",
          padding: "4px 10px", borderRadius: 999,
          border: "1px solid var(--rule)",
          fontFamily: "var(--mono)", letterSpacing: ".06em", fontWeight: 600
        }}
        onMouseEnter={(e) => { e.currentTarget.style.color = "var(--ink)"; e.currentTarget.style.borderColor = "var(--ink)"; }}
        onMouseLeave={(e) => { e.currentTarget.style.color = "var(--muted)"; e.currentTarget.style.borderColor = "var(--rule)"; }}>
          RÉSUMÉ
        </a>
        <button onClick={onToggleTheme} style={{
          all: "unset", cursor: "pointer",
          display: "flex", alignItems: "center", gap: 6,
          fontSize: 11, color: "var(--muted)",
          padding: "4px 10px", borderRadius: 999,
          border: "1px solid var(--rule)",
          fontFamily: "var(--mono)", letterSpacing: ".06em", fontWeight: 600
        }}>
          <PixelIcon name={theme === "dark" ? "sun" : "moon"} size={11} color="var(--muted)" />
          {theme === "dark" ? "LIGHT" : "DARK"}
        </button>
      </div>
    </header>);

}

// ----- Main App (unused — Root renders AppInner) -----

function AssistantLabel({ name = "MINI-LI" }) {
  return (
    <div style={{
      display: "flex", alignItems: "center", gap: 8,
      fontSize: 10, letterSpacing: ".12em", fontWeight: 600,
      color: "var(--muted)"
    }}>
      <div style={{
        width: 16, height: 16, borderRadius: "50%",
        background: "var(--accent)",
        display: "grid", placeItems: "center",
        color: "#fff", fontFamily: "var(--serif)", fontSize: 12, fontStyle: "italic", lineHeight: 1
      }}>L</div>
      {name}
    </div>);

}

function Composer({ value, onChange, onSubmit, suggestions, onPick, busy }) {
  return (
    <div style={{
      position: "fixed", bottom: 0, left: 0, right: 0,
      background: "var(--bg)",
      padding: "18px 20px 22px",
      zIndex: 5,
      borderTop: "1px solid var(--rule)",
      boxShadow: "0 -12px 24px -12px rgba(0,0,0,.12)"
    }}>
      <div style={{ maxWidth: 820, margin: "0 auto" }}>
        {/* Suggestions */}
        <div style={{
          display: "flex", gap: 8, flexWrap: "wrap",
          marginBottom: 12, justifyContent: "center"
        }}>
          {suggestions.map((s, i) =>
          <button key={i} onClick={() => onPick(s)} disabled={busy} style={{
            all: "unset", cursor: busy ? "not-allowed" : "pointer",
            fontSize: 11, fontFamily: "var(--mono)",
            color: "var(--ink)",
            padding: "7px 14px",
            background: "var(--card)",
            borderRadius: 999,
            border: "1px solid var(--rule)",
            opacity: busy ? .5 : 1,
            transition: "transform .15s"
          }}
          onMouseEnter={(e) => !busy && (e.currentTarget.style.transform = "translateY(-2px)")}
          onMouseLeave={(e) => e.currentTarget.style.transform = "translateY(0)"}>
            
              {s}
            </button>
          )}
        </div>

        {/* Input */}
        <form onSubmit={(e) => {e.preventDefault();onSubmit();}}
        style={{
          display: "flex", alignItems: "center",
          gap: 10, padding: "8px 10px 8px 18px",
          background: "var(--card)",
          borderRadius: 999,
          border: "1px solid var(--rule)",
          boxShadow: "0 8px 32px -12px rgba(0,0,0,.12)"
        }}>
          <PixelIcon name="sparkle" size={14} color="var(--muted)" />
          <input
            value={value}
            onChange={(e) => onChange(e.target.value)}
            placeholder="Ask about my work, experience, how to reach me…"
            disabled={busy}
            style={{
              flex: 1, border: 0, background: "transparent",
              fontFamily: "var(--mono)", fontSize: 13,
              color: "var(--ink)", outline: "none",
              padding: "8px 0"
            }} />
          
          <button type="submit" disabled={busy || !value.trim()} style={{
            all: "unset", cursor: busy ? "not-allowed" : "pointer",
            width: 36, height: 36, borderRadius: "50%",
            background: value.trim() && !busy ? "var(--accent)" : "var(--rule)",
            display: "grid", placeItems: "center",
            transition: "background .15s"
          }}>
            <PixelIcon name="arrow" size={12} color="#fff" />
          </button>
        </form>
        <div style={{
          fontSize: 10, textAlign: "center",
          marginTop: 8, letterSpacing: ".06em", color: "#8a8680"
        }}>
          answers sourced from my personal documentation · may make mistakes · built with care
        </div>
      </div>
    </div>);

}

// ----- Tweaks panel -----
function Tweaks({ tweaks, setTweak }) {
  const { TweaksPanel, TweakSection, TweakRadio, TweakColor } = window;
  if (!TweaksPanel) return null;
  return (
    <TweaksPanel>
      <TweakSection label="Theme" />
      <TweakRadio
        label="Mode"
        value={tweaks.theme}
        onChange={(v) => setTweak("theme", v)}
        options={[{ value: "light", label: "Light" }, { value: "dark", label: "Dark" }]} />
      
      <TweakSection label="Accent" />
      <TweakColor
        label="Accent color"
        value={tweaks.accent}
        onChange={(v) => setTweak("accent", v)} />
      
      <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginTop: 4 }}>
        {["#c03010", "#0a66c2", "#2e7d32", "#6a2da8", "#111111", "#e09a00"].map((c) =>
        <button key={c} onClick={() => setTweak("accent", c)} style={{
          all: "unset", cursor: "pointer",
          width: 22, height: 22, borderRadius: "50%",
          background: c,
          boxShadow: tweaks.accent === c ? "0 0 0 2px #fff, 0 0 0 3px #000" : "0 0 0 1px rgba(0,0,0,.15)"
        }} />
        )}
      </div>
    </TweaksPanel>);

}

// Root
function Root() {
  const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS);

  useEffect(() => {
    document.documentElement.setAttribute("data-theme", tweaks.theme || "light");
  }, [tweaks.theme]);

  useEffect(() => {
    document.documentElement.style.setProperty("--accent", tweaks.accent || "#c03010");
  }, [tweaks.accent]);

  return (
    <>
      <AppInner tweaks={tweaks} setTweak={setTweak} />
      <Tweaks tweaks={tweaks} setTweak={setTweak} />
    </>);

}

function AppInner({ tweaks, setTweak }) {
  // live clock
  const [now, setNow] = useState(new Date());
  useEffect(() => {
    const t = setInterval(() => setNow(new Date()), 1000 * 30);
    return () => clearInterval(t);
  }, []);
  const timeStr = useMemo(() => {
    const h24 = now.getHours();
    const m = now.getMinutes();
    const ampm = h24 >= 12 ? "pm" : "am";
    const h12 = h24 % 12 || 12;
    return `${h12}:${String(m).padStart(2, "0")} ${ampm}`;
  }, [now]);

  const [messages, setMessages] = useState([]);
  const [input, setInput] = useState("");
  const [busy, setBusy] = useState(false);
  const scrollRef = useRef(null);
  const bootedRef = useRef(false);

  function scrollToBottom() {
    requestAnimationFrame(() => {
      window.scrollTo({ top: document.body.scrollHeight, behavior: "smooth" });
    });
  }

  function findResponse(text) {
    const low = text.toLowerCase();
    const ordered = [...PROMPT_LIBRARY.slice(1), PROMPT_LIBRARY[0]];
    for (const p of ordered) {
      if (p.match.some((k) => low.includes(k))) return p;
    }
    return null;
  }

  async function submitAI(text, thinkingId) {
    try {
      const res = await fetch("/api/chat", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ message: text }),
      });
      const { reply } = await res.json();
      setMessages((m) => m.filter((x) => x.id !== thinkingId).concat({
        id: Date.now() + 2,
        role: "ai",
        text: reply ?? "I had trouble with that. Try rephrasing?",
      }));
    } catch {
      setMessages((m) => m.filter((x) => x.id !== thinkingId).concat({
        id: Date.now() + 2,
        role: "ai",
        text: "Sorry, I had trouble connecting. Try again in a moment.",
      }));
    }
    setBusy(false);
    setTimeout(() => scrollToBottom(), 60);
    setTimeout(() => scrollToBottom(), 300);
  }

  function submit(text, forcedRespId, silent = false) {
    if (!text.trim() || busy) return;
    const resp = forcedRespId ?
    PROMPT_LIBRARY.find((p) => p.id === forcedRespId) || findResponse(text) :
    findResponse(text);
    if (!silent) {
      const userMsg = { id: Date.now(), role: "user", text };
      setMessages((m) => [...m, userMsg]);
    }
    setInput("");
    setBusy(true);
    scrollToBottom();

    const thinkingId = Date.now() + 1;

    if (!resp) {
      setMessages((m) => [...m, { id: thinkingId, role: "thinking", label: "Thinking…" }]);
      scrollToBottom();
      submitAI(text, thinkingId);
      return;
    }

    const thinkingLabels = resp.thinking || ["Thinking…"];
    let step = 0;
    setMessages((m) => [...m, { id: thinkingId, role: "thinking", label: thinkingLabels[0] }]);
    scrollToBottom();

    const iv = setInterval(() => {
      step++;
      if (step < thinkingLabels.length) {
        setMessages((m) => m.map((x) => x.id === thinkingId ? { ...x, label: thinkingLabels[step] } : x));
      }
    }, 700);

    const totalDelay = Math.max(900, thinkingLabels.length * 700 + 300);
    setTimeout(() => {
      clearInterval(iv);
      setMessages((m) => m.filter((x) => x.id !== thinkingId).concat({
        id: Date.now() + 2,
        role: "assistant",
        respId: resp.id
      }));
      setBusy(false);
      setTimeout(() => scrollToBottom(), 60);
      setTimeout(() => scrollToBottom(), 300);
    }, totalDelay);
  }

  useEffect(() => {
    if (bootedRef.current) return;
    bootedRef.current = true;
    setTimeout(() => submit("Who are you?", "intro", true), 400);
  }, []);

  const suggestions = PROMPT_LIBRARY.slice(1).map((p) => p.prompt);

  return (
    <>
      <Header time={timeStr} theme={tweaks.theme || "light"}
      onToggleTheme={() => {
        const next = (tweaks.theme || "light") === "dark" ? "light" : "dark";
        localStorage.setItem("theme", next);
        setTweak("theme", next);
      }} />

      <main ref={scrollRef} style={{
        maxWidth: 820,
        margin: "0 auto",
        padding: "28px 20px 280px"
      }}>
        {(() => {
          let assistantCount = 0;
          return messages.map((msg) => {
            if (msg.role === "user") return <UserBubble key={msg.id} text={msg.text} />;
            if (msg.role === "thinking") return (
              <div key={msg.id} style={{ marginBottom: 14 }}>
                <Thinking label={msg.label} />
              </div>);
            if (msg.role === "ai") {
              const name = assistantCount++ === 0 ? "LIANNA" : "MINI-LI";
              return (
                <div key={msg.id} style={{ marginBottom: 28, animation: "fadeUp .4s ease-out" }}>
                  <AssistantLabel name={name} />
                  <div style={{ display: "flex", flexDirection: "column", gap: 12, marginTop: 10 }}>
                    <AIReply text={msg.text} />
                  </div>
                </div>);
            }

            const resp = PROMPT_LIBRARY.find((p) => p.id === msg.respId);
            if (!resp) return null;
            const name = assistantCount++ === 0 ? "LIANNA" : "MINI-LI";
            return (
              <div key={msg.id} style={{ marginBottom: 28, animation: "fadeUp .4s ease-out" }}>
                <AssistantLabel name={name} />
                <div style={{ display: "flex", flexDirection: "column", gap: 12, marginTop: 10 }}>
                  {resp.reply({ time: timeStr })}
                </div>
              </div>);
          });
        })()}

        {!busy && messages.length > 1 && <FooterMark />}
      </main>

      <Composer
        value={input}
        onChange={setInput}
        onSubmit={() => submit(input)}
        suggestions={suggestions}
        onPick={(s) => submit(s)}
        busy={busy} />
      

      <style>{`
        @keyframes fadeUp {
          from { opacity: 0; transform: translateY(8px); }
          to   { opacity: 1; transform: translateY(0); }
        }
        input::placeholder { color: var(--muted); }
        @media (max-width: 600px) {
          .r-grid { --grid-cols: 1 !important; }
        }
      `}</style>
    </>);

}

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