// =============================================================================
// JARVIS DASHBOARD — App shell
//
// Architecture:
//   - All data flows through window.useJarvisData(key) → the active adapter.
//   - All mutations flow through window.JD.mutate(method, ...args).
//   - Cross-tab interaction state (Jarvis drawer, prep checks, Store-Boss chat)
//     lives in SharedContext and is read via window.useShared().
//   - Per-tab UI lives in src/tabs/*.jsx and registers on window.JD_TABS.
//
// The shell itself contains zero business logic — no canned tasks, no fake
// counts, no hardcoded clients. Everything renders from adapter responses.
// =============================================================================

(function () {
  const { useState, useRef, useEffect, useCallback, useMemo } = React;
  const { C, TABS } = window.JD_THEME;
  const { Empty } = window.JD_STYLES;

  // ---- Shared interaction state --------------------------------------------
  const SharedContext = React.createContext(null);

  function SharedProvider({ children }) {
    // Jarvis drawer
    const [jarvisOpen, setJarvisOpen] = useState(false);
    const [jarvisInput, setJarvisInput] = useState("");
    const [jarvisMessages, setJarvisMessages] = useState([]);
    const [voiceMode, setVoiceMode] = useState(false);
    const jarvisRef = useRef(null);

    // 72-hr prep checks (Dashboard + Calendar + top-bar popup all share)
    const [prepChecks, setPrepChecks] = useState({});
    const [meetingAlertOpen, setMeetingAlertOpen] = useState(false);

    // Store Boss chat (Dashboard inline + Store tab full panel)
    const [storeMsg, setStoreMsg] = useState("");
    const [storeMsgs, setStoreMsgs] = useState([]);

    const sendJarvis = useCallback(async () => {
      if (!jarvisInput.trim()) return;
      const msg = jarvisInput;
      setJarvisMessages(m => [...m, { role: "user", msg }]);
      setJarvisInput("");
      try {
        const reply = await window.JD.mutate("sendJarvisMessage", msg);
        if (reply && reply.msg) setJarvisMessages(m => [...m, reply]);
      } catch (e) {
        setJarvisMessages(m => [...m, { role: "assistant", msg: "Adapter error: " + e.message }]);
      }
      setTimeout(() => { if (jarvisRef.current) jarvisRef.current.scrollTop = jarvisRef.current.scrollHeight; }, 50);
    }, [jarvisInput]);

    const sendStoreBoss = useCallback(async () => {
      if (!storeMsg.trim()) return;
      const msg = storeMsg;
      setStoreMsgs(m => [...m, { role: "user", msg }]);
      setStoreMsg("");
      try {
        const reply = await window.JD.mutate("sendStoreBossMessage", msg);
        if (reply && reply.msg) setStoreMsgs(m => [...m, reply]);
      } catch (e) {
        setStoreMsgs(m => [...m, { role: "assistant", msg: "Adapter error: " + e.message }]);
      }
    }, [storeMsg]);

    const value = useMemo(() => ({
      jarvisOpen, setJarvisOpen, jarvisInput, setJarvisInput, jarvisMessages, setJarvisMessages,
      voiceMode, setVoiceMode, jarvisRef, sendJarvis,
      prepChecks, setPrepChecks, meetingAlertOpen, setMeetingAlertOpen,
      storeMsg, setStoreMsg, storeMsgs, setStoreMsgs, sendStoreBoss,
    }), [
      jarvisOpen, jarvisInput, jarvisMessages, voiceMode,
      prepChecks, meetingAlertOpen,
      storeMsg, storeMsgs,
      sendJarvis, sendStoreBoss,
    ]);

    return <SharedContext.Provider value={value}>{children}</SharedContext.Provider>;
  }

  window.useShared = () => React.useContext(SharedContext);

  // ---- Top bar -------------------------------------------------------------
  function TopBar({ tab, setTab }) {
    const { jarvisOpen, setJarvisOpen, meetingAlertOpen, setMeetingAlertOpen, prepChecks, setPrepChecks } = window.useShared();
    const { data: user } = window.useJarvisData("user");
    const { data: emails } = window.useJarvisData("emails");
    const { data: meetings72 } = window.useJarvisData("meetings72");
    const { data: calEvents } = window.useJarvisData("calendarEvents");
    const { data: highest } = window.useJarvisData("highestValueTask");

    const today = new Date();
    const dateLabel = today.toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric", year: "numeric" });
    const unread = (emails || []).length;
    const eventsThisWeek = Object.values(calEvents || {}).flat().length;
    const u = user || {};
    const m72 = meetings72 || [];

    const { bgg, br } = window.JD_STYLES;
    const { EVT } = window.JD_THEME;

    return (
      <>
        <div style={{ background: C.surface, borderBottom: "0.5px solid rgba(222,214,185,0.06)", padding: "8px 20px", display: "flex", alignItems: "center", justifyContent: "space-between", flexShrink: 0, position: "sticky", top: 0, zIndex: 100 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 20 }}>
            <div style={{ fontSize: 15, color: C.cream, letterSpacing: "0.06em" }}>{u.org || "Lovejoy Innovative Planning"}</div>
            <div style={{ fontSize: 14, color: C.muted }}>{dateLabel}</div>
          </div>
          <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
            <div style={pillStyle(C.red, 0.1)}>{unread} unread</div>
            <div style={pillStyle(C.yellow, 0.1)}>0 overdue</div>
            <div style={pillStyle(C.blue, 0.1)}>{eventsThisWeek} events this week</div>
            <div style={{ position: "relative" }}>
              <button onClick={() => setMeetingAlertOpen(!meetingAlertOpen)} style={{ ...pillStyle(C.red, 0.1), borderColor: "rgba(224,82,82,0.35)", cursor: "pointer", fontFamily: "Georgia,serif" }}>
                Meeting Alert ({m72.filter((_, i) => prepChecks[i] !== true).length})
              </button>
              {meetingAlertOpen && (
                <div style={{ position: "absolute", right: 0, top: "calc(100% + 6px)", background: C.card, border: "0.5px solid rgba(224,82,82,0.3)", borderRadius: 10, padding: 12, minWidth: 280, zIndex: 200, boxShadow: "0 8px 24px rgba(0,0,0,0.4)" }}>
                  <div style={{ fontSize: 13, color: C.red, letterSpacing: "0.18em", textTransform: "uppercase", marginBottom: 10 }}>Upcoming Meetings</div>
                  {m72.length === 0 ? <Empty label="None" /> : m72.map((m, i) => (
                    <div key={i} style={{ padding: "8px 0", borderBottom: "0.5px solid " + C.border, opacity: prepChecks[i] === true ? 0.4 : 1 }}>
                      <div style={{ fontSize: 15, color: prepChecks[i] === true ? C.muted : C.cream, textDecoration: prepChecks[i] === true ? "line-through" : "none" }}>{m.title}</div>
                      <div style={{ fontSize: 13, color: C.muted, marginBottom: 6 }}>{m.date} · {m.time}</div>
                      {prepChecks[i] !== true && (
                        <div style={{ display: "flex", gap: 5 }}>
                          <button onClick={() => setPrepChecks(p => ({ ...p, [i]: true }))} style={{ ...bgg, fontSize: 13, padding: "3px 10px" }}>Prepped</button>
                          <button onClick={() => setPrepChecks(p => ({ ...p, [i]: "no" }))} style={{ ...br, fontSize: 13, padding: "3px 10px" }}>Need Prep</button>
                        </div>
                      )}
                    </div>
                  ))}
                </div>
              )}
            </div>
            <div style={{ width: 28, height: 28, borderRadius: "50%", background: "rgba(159,117,9,0.2)", border: "0.5px solid rgba(159,117,9,0.4)", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 15, fontWeight: 500, color: C.gold, cursor: "pointer" }}>{u.initials || "—"}</div>
          </div>
        </div>

        <div style={{ background: "rgba(159,117,9,0.08)", borderBottom: "0.5px solid rgba(159,117,9,0.15)", padding: "7px 20px", display: "flex", alignItems: "center", gap: 10, flexShrink: 0, position: "sticky", top: 42, zIndex: 99 }}>
          <div style={{ fontSize: 13, color: C.gold, letterSpacing: "0.18em", textTransform: "uppercase", flexShrink: 0 }}>Today</div>
          <div style={{ fontSize: 15, color: "rgba(222,214,185,0.7)" }}>
            {highest
              ? <>Highest value task: <span style={{ color: C.cream }}>{highest}</span></>
              : <span style={{ fontStyle: "italic" }}>Run morning brief to set highest-value task</span>}
          </div>
        </div>

        <div style={{ background: C.surface, borderBottom: "0.5px solid " + C.border, display: "flex", padding: "0 20px", flexShrink: 0, position: "sticky", top: 84, zIndex: 98, overflowX: "auto" }}>
          {TABS.map(t => (
            <div key={t} onClick={() => t === "Jarvis" ? setJarvisOpen(!jarvisOpen) : setTab(t)} style={{ padding: "11px 18px", fontSize: 14, letterSpacing: "0.12em", textTransform: "uppercase", color: (tab === t && t !== "Jarvis") || (t === "Jarvis" && jarvisOpen) ? C.gold : "rgba(222,214,185,0.78)", borderBottom: "2px solid " + ((tab === t && t !== "Jarvis") || (t === "Jarvis" && jarvisOpen) ? C.gold : "transparent"), cursor: "pointer", fontFamily: "Georgia,serif", whiteSpace: "nowrap" }}>
              {t}
            </div>
          ))}
        </div>
      </>
    );
  }

  function pillStyle(color, alpha) {
    return {
      fontSize: 14,
      color: "rgba(222,214,185,0.7)",
      padding: "3px 10px",
      background: hexA(color, alpha),
      borderRadius: 10,
      border: "0.5px solid " + hexA(color, 0.2),
    };
  }
  function hexA(hex, a) {
    // approximate alpha; we use rgba strings for known colors
    const rgb = parseInt(hex.replace("#", ""), 16);
    const r = (rgb >> 16) & 0xff, g = (rgb >> 8) & 0xff, b = rgb & 0xff;
    return `rgba(${r},${g},${b},${a})`;
  }

  // ---- Jarvis drawer -------------------------------------------------------
  function JarvisDrawer() {
    const { jarvisOpen, setJarvisOpen, jarvisInput, setJarvisInput, jarvisMessages, voiceMode, setVoiceMode, jarvisRef, sendJarvis } = window.useShared();
    const { data: user } = window.useJarvisData("user");
    const { inp, bg, Empty } = window.JD_STYLES;
    if (!jarvisOpen) return null;
    return (
      <div style={{ position: "fixed", right: 0, top: 0, bottom: 0, width: 320, background: C.surface, borderLeft: "0.5px solid " + C.border, display: "flex", flexDirection: "column", zIndex: 150, boxShadow: "-8px 0 32px rgba(0,0,0,0.5)" }}>
        <div style={{ padding: "14px 16px", borderBottom: "0.5px solid " + C.border, display: "flex", alignItems: "center", justifyContent: "space-between" }}>
          <div>
            <div style={{ fontSize: 17, color: C.gold }}>Jarvis</div>
            <div style={{ fontSize: 13, color: C.muted, marginTop: 1 }}>Executive AI Assistant</div>
          </div>
          <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
            <button onClick={() => setVoiceMode(!voiceMode)} style={{ fontSize: 14, padding: "4px 10px", background: voiceMode ? "rgba(62,207,142,0.15)" : "transparent", border: "0.5px solid " + (voiceMode ? "rgba(62,207,142,0.4)" : C.border), borderRadius: 6, color: voiceMode ? C.green : C.muted, cursor: "pointer", fontFamily: "Georgia,serif" }}>
              {voiceMode ? "● Listening" : "Voice"}
            </button>
            <button onClick={() => setJarvisOpen(false)} style={{ background: "transparent", border: "none", color: C.muted, cursor: "pointer", fontSize: 26, padding: 0, lineHeight: 1 }}>×</button>
          </div>
        </div>
        <div ref={jarvisRef} style={{ flex: 1, overflow: "auto", padding: "12px 14px", display: "flex", flexDirection: "column", gap: 10 }}>
          {jarvisMessages.length === 0 && <Empty label="Say hi to Jarvis" sub="Threads will persist once the Obsidian adapter is wired" />}
          {jarvisMessages.map((m, i) => (
            <div key={i} style={{ display: "flex", gap: 8, alignItems: "flex-start" }}>
              <div style={{ width: 22, height: 22, borderRadius: "50%", background: m.role === "user" ? "rgba(222,214,185,0.1)" : "rgba(159,117,9,0.2)", border: "0.5px solid " + (m.role === "user" ? "rgba(222,214,185,0.2)" : "rgba(159,117,9,0.35)"), display: "flex", alignItems: "center", justifyContent: "center", fontSize: 13, flexShrink: 0, color: m.role === "user" ? "rgba(222,214,185,0.7)" : C.gold }}>
                {m.role === "user" ? ((user && user.initials && user.initials[0]) || "U") : "J"}
              </div>
              <div style={{ background: m.role === "user" ? "rgba(222,214,185,0.05)" : "rgba(159,117,9,0.07)", border: "0.5px solid " + (m.role === "user" ? "rgba(222,214,185,0.1)" : "rgba(159,117,9,0.15)"), borderRadius: 8, padding: "8px 10px", flex: 1, fontSize: 15, color: "rgba(222,214,185,0.82)", lineHeight: 1.6 }}>
                {m.msg}
              </div>
            </div>
          ))}
        </div>
        <div style={{ padding: "10px 14px", borderTop: "0.5px solid " + C.border }}>
          <div style={{ display: "flex", gap: 8 }}>
            <input value={jarvisInput} onChange={e => setJarvisInput(e.target.value)} onKeyDown={e => e.key === "Enter" && sendJarvis()} placeholder="Ask Jarvis anything..." style={{ ...inp, flex: 1 }} />
            <button onClick={sendJarvis} style={bg}>Send</button>
          </div>
        </div>
      </div>
    );
  }

  // ---- App root ------------------------------------------------------------
  function App() {
    const [tab, setTab] = useState("Dashboard");
    const tabs = window.JD_TABS || {};
    const TabComponent = tabs[tab] || tabs.Dashboard;

    // Body uses cream background for content tabs (matches design).
    return (
      <SharedProvider>
        <div style={{ fontFamily: "Georgia, Palatino, serif", background: C.bg, height: "100vh", color: C.cream, display: "flex", flexDirection: "column", fontSize: 17, overflow: "hidden" }}>
          <TopBar tab={tab} setTab={setTab} />
          <JarvisDrawer />
          <div style={{ flex: 1, overflow: "auto", padding: 24, background: C.cream }}>
            {TabComponent ? <TabComponent /> : <div>Tab missing: {tab}</div>}
          </div>
        </div>
      </SharedProvider>
    );
  }

  // Load tab modules then mount. We expect tab scripts to load before app.jsx,
  // but they may use a deferred registration pattern — wait one tick.
  function mount() {
    if (!window.JD_TABS || !window.JD_TABS.Dashboard) {
      // try again next tick
      return requestAnimationFrame(mount);
    }
    ReactDOM.createRoot(document.getElementById("root")).render(<App />);
  }
  mount();
})();
