// chat-ui.jsx — shared iMessage chat surface + animated hero phone loop
// Exports (to window): ChatScreen, ChatBubble, TypingBubble, ComposeBar, HeroPhone, useChatScript, nowTime, nowStamp

const { useState, useEffect, useRef, useCallback } = React;

// ── Time helpers ─────────────────────────────────────────────

function nowTime() {
  const d = new Date();
  let h = d.getHours() % 12;
  if (h === 0) h = 12;
  return h + ":" + String(d.getMinutes()).padStart(2, "0");
}

function nowStamp() {
  const d = new Date();
  const ampm = d.getHours() >= 12 ? "PM" : "AM";
  return "Today " + nowTime() + " " + ampm;
}

// ── Primitives ──────────────────────────────────────────────

function ChatBubble({ from, children }) {
  return (
    <div className={"bubble " + (from === "me" ? "bubble-me" : "bubble-them")}>
      {children}
    </div>
  );
}

function TypingBubble({ from }) {
  return (
    <div className={"bubble " + (from === "me" ? "bubble-me" : "bubble-them")}>
      <div className="typing">
        <span className="typing-dot"></span>
        <span className="typing-dot"></span>
        <span className="typing-dot"></span>
      </div>
    </div>
  );
}

function CallIcon() {
  return (
    <span className="chat-call" aria-label="Call">
      <svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor">
        <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path>
      </svg>
    </span>
  );
}

// tone: "brand" (accent circle, initials) | "plain" (iOS gray circle, e.g. emoji)
function ChatScreen({ contact, avatar, tone = "brand", callIcon = false, compact = false, children, threadRef, footer }) {
  return (
    <div className="chat-screen">
      <div className={"chat-header" + (compact ? " chat-header-compact" : "")}>
        <div className={"chat-avatar" + (tone === "plain" ? " chat-avatar-plain" : "")}>{avatar}</div>
        <div className="chat-contact">
          <span>{contact}</span>
        </div>
        {callIcon && <CallIcon />}
      </div>
      <div className="chat-thread" ref={threadRef}>
        {children}
      </div>
      {footer}
    </div>
  );
}

// ── iMessage compose bar ──────────────────────────────

function ComposeBar({ text, keyboard, low }) {
  return (
    <div className={"compose" + (keyboard ? " compose-kb" : "") + (low ? " compose-low" : "")}>
      <div className={"compose-input" + (text ? " has-text" : "")}>
        {text || "Text Message"}
        {text ? <span className="compose-caret"></span> : null}
      </div>
      <span className={"compose-send" + (text ? " active" : "")}>
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
          <path d="M12 19V5"></path><path d="M5 12l7-7 7 7"></path>
        </svg>
      </span>
    </div>
  );
}

// ── Scripted conversation hook ──────────────────────────────

function chatSpeed() {
  const v = parseFloat(
    getComputedStyle(document.documentElement).getPropertyValue("--mila-chat-speed")
  );
  return isNaN(v) || v <= 0 ? 1 : v;
}

function useChatScript(script, { loop = true, loopPauseMs = 3000, gapMs = 700, rate = 1 } = {}) {
  const [messages, setMessages] = useState([]);
  const [typingFrom, setTypingFrom] = useState(null);

  useEffect(() => {
    let cancelled = false;
    let timer = null;
    const wait = (ms) =>
      new Promise((res) => { timer = setTimeout(res, ms / (chatSpeed() * rate)); });

    async function run() {
      while (!cancelled) {
        setMessages([]);
        setTypingFrom(null);
        await wait(900);
        for (let i = 0; i < script.length; i++) {
          if (cancelled) return;
          const step = script[i];
          if (step.typingMs) {
            setTypingFrom(step.from);
            await wait(step.typingMs);
            if (cancelled) return;
            setTypingFrom(null);
          }
          setMessages((m) => [...m, step]);
          await wait(gapMs);
        }
        if (!loop) return;
        await wait(loopPauseMs);
      }
    }
    run();
    return () => { cancelled = true; clearTimeout(timer); };
  }, []);

  return { messages, typingFrom };
}

// ── Hero phone ──────────────────────────────────────────────

const HERO_SCRIPT = [
  { from: "me", text: "Hey, are you open on Sundays?" },
  { from: "them", text: "Hi! We\u2019re open Sunday 9am-3pm. Anything else I can help with?", typingMs: 1200 },
  { from: "me", text: "Do you have any drop-in classes?" },
  { from: "them", text: "Yes! Drop-ins are $20. You can walk in anytime - no reservation needed.", typingMs: 1500 },
  { from: "me", text: "Perfect, thanks!" },
  { from: "them", text: "Of course! See you soon \uD83D\uDE0A", typingMs: 1000 },
];

function HeroPhone() {
  const [messages, setMessages] = useState([]);
  const [typingFrom, setTypingFrom] = useState(null);
  const [compose, setCompose] = useState("");
  const threadRef = useRef(null);
  const RATE = 0.8; // run at 80% speed

  useEffect(() => {
    let cancelled = false;
    let timer = null;
    const wait = (ms) =>
      new Promise((res) => { timer = setTimeout(res, ms / (chatSpeed() * RATE)); });

    async function run() {
      while (!cancelled) {
        setMessages([]); setTypingFrom(null); setCompose("");
        await wait(900);
        for (const step of HERO_SCRIPT) {
          if (cancelled) return;
          if (step.from === "me") {
            await wait(420);
            for (let i = 1; i <= step.text.length; i++) {
              if (cancelled) return;
              setCompose(step.text.slice(0, i));
              await wait(30);
            }
            await wait(260);
            if (cancelled) return;
            setCompose("");
            setMessages((m) => [...m, step]);
          } else {
            setTypingFrom("them");
            await wait(step.typingMs);
            if (cancelled) return;
            setTypingFrom(null);
            setMessages((m) => [...m, step]);
          }
          await wait(700);
        }
        await wait(3200);
      }
    }
    run();
    return () => { cancelled = true; clearTimeout(timer); };
  }, []);

  useEffect(() => {
    const el = threadRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [messages, typingFrom, compose]);

  return (
    <IOSDevice width={360} height={620} time={nowTime()} island={{ height: 30 }}>
      <ChatScreen contact="Your Business" avatar="YB" callIcon threadRef={threadRef}
        footer={<ComposeBar text={compose} />}>
        <div className="chat-stamp">{nowStamp()}</div>
        {messages.map((m, i) => (
          <ChatBubble key={i} from={m.from}>{m.text}</ChatBubble>
        ))}
        {typingFrom && <TypingBubble from={typingFrom} />}
      </ChatScreen>
    </IOSDevice>
  );
}

const heroRoot = document.getElementById("hero-phone-root");
if (heroRoot) ReactDOM.createRoot(heroRoot).render(<HeroPhone />);

Object.assign(window, { ChatScreen, ChatBubble, TypingBubble, ComposeBar, useChatScript, HeroPhone, nowTime, nowStamp });
