// Animated iMessage-style thread component.
// Props: messages (array), accent (CSS color), bg, fg, mode ('imessage' | 'plain'), autoplay (bool), loop (bool)
// Renders a phone-style chat that types messages out one at a time.

const Thread = ({
  messages,
  accent = "#0A84FF",       // user bubble color
  themBg = "#E9E9EB",       // their bubble color
  themFg = "#000",
  meFg = "#fff",
  bg = "#fff",
  font = "-apple-system, BlinkMacSystemFont, 'SF Pro Text', system-ui, sans-serif",
  autoplay = true,
  loop = true,
  speed = 1,                // 1 = normal
  showHeader = true,
  headerName = "magica",
  headerSub = "iMessage",
  headerAvatar = null,      // url or null
  radius = 18,
  bubbleRadius = 20,
  showTail = true,
  metaColor = "rgba(0,0,0,0.45)",
  style = {},
  className = "",
}) => {
  const [shown, setShown] = React.useState([]); // array of { ...msg, typed: string, done: bool }
  const [phase, setPhase] = React.useState("idle"); // 'typing-them' | 'typing-me' | 'idle'
  const scrollRef = React.useRef(null);
  const cycleRef = React.useRef(0);

  React.useEffect(() => {
    if (!autoplay) return;
    let cancelled = false;
    let timers = [];
    const wait = (ms) => new Promise((r) => {
      const t = setTimeout(r, ms / speed);
      timers.push(t);
    });

    async function run() {
      while (!cancelled) {
        cycleRef.current += 1;
        const cycle = cycleRef.current;
        if (cancelled) return;
        setShown([]);
        await wait(600);
        for (let i = 0; i < messages.length; i++) {
          if (cancelled || cycleRef.current !== cycle) return;
          const m = messages[i];
          // typing indicator for "them" only
          if (m.from === "them") {
            setPhase("typing-them");
            const baseDelay = 700 + Math.min(m.text.length * 8, 1400);
            await wait(baseDelay);
            if (cancelled || cycleRef.current !== cycle) return;
          } else {
            await wait(400);
          }
          setPhase("idle");
          // append message immediately (no per-char typing — keeps it snappy)
          setShown((prev) => [...prev, { ...m, done: true }]);
          await wait(m.from === "them" ? 900 : 600);
        }
        if (!loop) return;
        await wait(3000);
      }
    }
    run();
    return () => {
      cancelled = true;
      timers.forEach(clearTimeout);
    };
  }, [messages, autoplay, loop, speed]);

  React.useEffect(() => {
    if (scrollRef.current) {
      scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
    }
  }, [shown, phase]);

  const headerEl = showHeader && (
    <div style={{
      display: "flex", flexDirection: "column", alignItems: "center",
      padding: "14px 12px 10px", borderBottom: "1px solid rgba(0,0,0,0.06)",
      background: bg, position: "sticky", top: 0, zIndex: 2,
    }}>
      <div style={{
        width: 44, height: 44, borderRadius: 22,
        background: headerAvatar ? `url(${headerAvatar}) center/cover` : "linear-gradient(135deg,#FFD86B,#FF8A3D)",
        display: "flex", alignItems: "center", justifyContent: "center",
        fontSize: 22, color: "#fff", fontWeight: 600,
      }}>
        {!headerAvatar && "m"}
      </div>
      <div style={{ fontSize: 11, marginTop: 4, color: "#000", fontWeight: 500 }}>{headerName}</div>
      <div style={{ fontSize: 10, color: "rgba(0,0,0,0.45)" }}>{headerSub}</div>
    </div>
  );

  return (
    <div className={className} style={{
      background: bg, borderRadius: radius, overflow: "hidden",
      fontFamily: font, color: themFg, display: "flex", flexDirection: "column",
      ...style,
    }}>
      {headerEl}
      <div ref={scrollRef} style={{
        flex: 1, overflowY: "auto", padding: "14px 12px 16px",
        display: "flex", flexDirection: "column", gap: 4,
        scrollbarWidth: "none",
      }}>
        <style>{`.thread-scroll::-webkit-scrollbar{display:none}`}</style>
        {shown.map((m, i) => {
          const prev = shown[i - 1];
          const next = shown[i + 1];
          const sameFromPrev = prev && prev.from === m.from;
          const sameFromNext = next && next.from === m.from;
          const isMe = m.from === "me";
          const tail = showTail && !sameFromNext;
          return (
            <div key={i} style={{
              display: "flex", flexDirection: "column",
              alignItems: isMe ? "flex-end" : "flex-start",
              marginTop: sameFromPrev ? 2 : 8,
            }}>
              {m.meta && (
                <div style={{
                  fontSize: 10, color: metaColor, marginBottom: 4,
                  alignSelf: isMe ? "flex-end" : "flex-start",
                  fontFamily: "ui-monospace, SFMono-Regular, monospace",
                  letterSpacing: 0.2,
                }}>
                  {m.meta}
                </div>
              )}
              <div style={{
                maxWidth: "78%",
                background: isMe ? accent : themBg,
                color: isMe ? meFg : themFg,
                padding: "8px 13px",
                fontSize: 14.5,
                lineHeight: 1.32,
                borderRadius: bubbleRadius,
                borderBottomRightRadius: isMe && tail ? 6 : bubbleRadius,
                borderBottomLeftRadius: !isMe && tail ? 6 : bubbleRadius,
                wordWrap: "break-word",
                animation: "msgIn 280ms cubic-bezier(.22,1,.36,1)",
                transformOrigin: isMe ? "bottom right" : "bottom left",
              }}>
                {m.text}
              </div>
            </div>
          );
        })}
        {phase === "typing-them" && (
          <div style={{
            display: "flex", alignItems: "center",
            background: themBg, padding: "10px 14px",
            borderRadius: bubbleRadius, alignSelf: "flex-start",
            gap: 4, marginTop: 6, animation: "msgIn 200ms ease-out",
          }}>
            <Dot delay={0} />
            <Dot delay={160} />
            <Dot delay={320} />
          </div>
        )}
      </div>
      <style>{`
        @keyframes msgIn {
          0% { opacity: 0; transform: translateY(6px) scale(0.96); }
          100% { opacity: 1; transform: translateY(0) scale(1); }
        }
        @keyframes typingDot {
          0%, 60%, 100% { opacity: 0.25; transform: translateY(0); }
          30% { opacity: 1; transform: translateY(-2px); }
        }
      `}</style>
    </div>
  );
};

const Dot = ({ delay }) => (
  <span style={{
    width: 6, height: 6, borderRadius: 3, background: "rgba(0,0,0,0.45)",
    display: "inline-block",
    animation: `typingDot 1.2s ${delay}ms infinite ease-in-out`,
  }} />
);

window.Thread = Thread;
