/* Office Sidekick — App shell, global state, sidebar, routing */

const { useState, useEffect, useRef, useCallback, useMemo, createContext, useContext } = React;

/* ============================================================
   TOOL REGISTRY (single source of truth)

   compact:        has a small interactive widget for the dashboard
   defaultPinned:  shown on dashboard by default (until user unpins)
   ============================================================ */
const TOOLS = [
  // Focus
  { id: "pomodoro",     name: "Pomodoro",        cat: "focus",    icon: "🍅", desc: "25-minute focus blocks with breaks.", kw: "timer break", color: "amber", compact: true, defaultPinned: true },
  { id: "focus-mode",   name: "Focus Mode",      cat: "focus",    icon: "🎯", desc: "Full-screen, distraction-free session.", kw: "deep work", color: "amber" },
  { id: "stopwatch",    name: "Stopwatch",       cat: "focus",    icon: "⏱️", desc: "Count up with laps and total.", kw: "timer", compact: true, isNew: true },

  // Break time
  { id: "watercooler",  name: "Watercooler",     cat: "break",    icon: "☕", desc: "Dad jokes, fun facts, good news, sports trivia.", kw: "fun joke break", color: "violet", compact: true, defaultPinned: true, isNew: true },

  // Write & think
  { id: "scratchpad",   name: "Scratchpad",      cat: "write",    icon: "🗒️", desc: "Quick notes that vanish on close.", kw: "notes jot session", color: "violet", compact: true },
  { id: "markdown",     name: "Markdown",        cat: "write",    icon: "🧾", desc: "Live preview as you type.", kw: "md preview" },
  { id: "prompt",       name: "Prompt Wizard",   cat: "write",    icon: "🪄", desc: "Battle-tested prompts that beat L7 defects.", kw: "ai claude gpt llm", color: "violet" },
  { id: "json-tools",   name: "JSON Tools",      cat: "write",    icon: "{ }", desc: "Validate, format, minify, diff.", kw: "format pretty", isNew: true },
  { id: "regex",        name: "Regex Tester",    cat: "write",    icon: "🔎", desc: "Live matches highlighted as you type.", kw: "regular expression", isNew: true },
  { id: "cleanup",      name: "Text Cleanup",    cat: "write",    icon: "🧼", desc: "Strip double spaces, smart quotes, weird line breaks.", kw: "whitespace format", isNew: true },

  // Live data
  { id: "weather",      name: "Weather",         cat: "live",     icon: "🌤️", desc: "Current conditions for any city.", kw: "temperature climate", color: "green", compact: true, isNew: true },
  { id: "fx",           name: "FX Rates",        cat: "live",     icon: "💱", desc: "Live currency conversion.", kw: "money exchange forex", color: "amber", compact: true, isNew: true },
  { id: "crypto",       name: "Crypto Spot",     cat: "live",     icon: "₿",  desc: "Real-time crypto prices.", kw: "bitcoin ethereum binance", compact: true, isNew: true },

  // Meetings
  { id: "meeting-cost", name: "Meeting Cost",    cat: "meetings", icon: "💸", desc: "How much this meeting is costing.", kw: "money calculator", color: "amber" },
  { id: "world-clock",  name: "World Clock",     cat: "meetings", icon: "🌍", desc: "Pinned cities + working-hour overlap.", kw: "time zones", color: "green", compact: true, defaultPinned: true },
  { id: "mirror",       name: "Mirror",          cat: "meetings", icon: "🪞", desc: "Webcam check before a call.", kw: "camera video selfie" },

  // Utilities
  { id: "sheets-lookup", name: "Sheets Formula", cat: "utility",  icon: "📊", desc: "Cross-sheet VLOOKUP / XLOOKUP / IMPORTRANGE, generated.", kw: "google excel formula", isNew: true },
  { id: "password",     name: "Password Gen",    cat: "utility",  icon: "🔑", desc: "Strong, configurable passwords.", kw: "secure crypto" },
  { id: "unit",         name: "Unit Converter",  cat: "utility",  icon: "🧮", desc: "Length, weight, volume, temperature.", kw: "convert measure" },
];

const CATEGORIES = [
  { id: "focus",    label: "Focus" },
  { id: "break",    label: "Break time" },
  { id: "write",    label: "Write & think" },
  { id: "live",     label: "Live data" },
  { id: "meetings", label: "Meetings" },
  { id: "utility",  label: "Utilities" },
];

const TOOL_BY_ID = Object.fromEntries(TOOLS.map(t => [t.id, t]));

/* ============================================================
   GLOBAL STATE (session-only — no persistence)
   ============================================================ */
const AppCtx = createContext(null);
const useApp = () => useContext(AppCtx);

function useAppState() {
  // Pomodoro (lives at app level so it keeps running across views)
  const [pomo, setPomo] = useState({
    mode: "focus",          // focus | short | long
    focus: 25, short: 5, long: 15,
    cycles: 4,
    sessionIdx: 1,
    remainingMs: 25 * 60000,
    totalMs: 25 * 60000,
    running: false,
    startedAt: null,
    bell: true,
  });
  const pomoRef = useRef(pomo);
  pomoRef.current = pomo;

  useEffect(() => {
    if (!pomo.running) return;
    const id = setInterval(() => {
      const p = pomoRef.current;
      const now = Date.now();
      const elapsed = now - p.startedAt;
      const next = { ...p, startedAt: now, remainingMs: Math.max(0, p.remainingMs - elapsed) };
      if (next.remainingMs <= 0) {
        if (p.bell) playBell();
        if (p.mode === "focus") {
          if (p.sessionIdx >= p.cycles) {
            setPomo({ ...next, mode: "long", totalMs: p.long * 60000, remainingMs: p.long * 60000, running: false });
          } else {
            setPomo({ ...next, mode: "short", totalMs: p.short * 60000, remainingMs: p.short * 60000, running: false });
          }
        } else if (p.mode === "short") {
          setPomo({ ...next, sessionIdx: p.sessionIdx + 1, mode: "focus", totalMs: p.focus * 60000, remainingMs: p.focus * 60000, running: false });
        } else {
          setPomo({ ...next, sessionIdx: 1, mode: "focus", totalMs: p.focus * 60000, remainingMs: p.focus * 60000, running: false });
        }
      } else {
        setPomo(next);
      }
    }, 250);
    return () => clearInterval(id);
  }, [pomo.running]);

  const startPomo = useCallback((modeOverride) => {
    setPomo(p => {
      const mode = modeOverride || p.mode;
      const dur = (mode === "focus" ? p.focus : mode === "short" ? p.short : p.long) * 60000;
      const remaining = mode === p.mode ? p.remainingMs : dur;
      return { ...p, mode, totalMs: dur, remainingMs: remaining, running: true, startedAt: Date.now() };
    });
  }, []);
  const pausePomo = useCallback(() => setPomo(p => ({ ...p, running: false, startedAt: null })), []);
  const resetPomo = useCallback(() => setPomo(p => ({
    ...p, running: false, startedAt: null, mode: "focus", sessionIdx: 1,
    totalMs: p.focus * 60000, remainingMs: p.focus * 60000
  })), []);
  const skipPomo = useCallback(() => setPomo(p => {
    if (p.mode === "focus") {
      if (p.sessionIdx >= p.cycles) {
        return { ...p, running: false, mode: "long", totalMs: p.long * 60000, remainingMs: p.long * 60000 };
      }
      return { ...p, running: false, mode: "short", totalMs: p.short * 60000, remainingMs: p.short * 60000 };
    }
    if (p.mode === "short") {
      return { ...p, running: false, sessionIdx: p.sessionIdx + 1, mode: "focus", totalMs: p.focus * 60000, remainingMs: p.focus * 60000 };
    }
    return { ...p, running: false, sessionIdx: 1, mode: "focus", totalMs: p.focus * 60000, remainingMs: p.focus * 60000 };
  }), []);

  // Scratchpad
  const [scratch, setScratch] = useState("");

  // Pinned tools on dashboard (session-only, starts with defaultPinned set)
  const [pinned, setPinned] = useState(() => TOOLS.filter(t => t.defaultPinned).map(t => t.id));
  const togglePin = useCallback((id) => {
    setPinned(p => p.includes(id) ? p.filter(x => x !== id) : [...p, id]);
  }, []);
  const isPinned = useCallback((id) => pinned.includes(id), [pinned]);

  // Customize mode (shows pin handles on tool tiles, prominent "remove" on widgets)
  const [customizing, setCustomizing] = useState(false);

  // Add-widget picker open
  const [addOpen, setAddOpen] = useState(false);

  // Recent tools
  const [recent, setRecent] = useState(["pomodoro", "watercooler", "world-clock"]);
  const recordUse = useCallback((id) => {
    setRecent(r => [id, ...r.filter(x => x !== id)].slice(0, 6));
  }, []);

  // Route
  const [route, setRouteState] = useState("dashboard");
  const setRoute = useCallback((id) => {
    setRouteState(id);
    if (TOOL_BY_ID[id]) recordUse(id);
    window.scrollTo(0, 0);
  }, [recordUse]);

  // Command palette open
  const [cmdOpen, setCmdOpen] = useState(false);

  // Live tick
  const [now, setNow] = useState(new Date());
  useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(id);
  }, []);

  return {
    pomo, startPomo, pausePomo, resetPomo, skipPomo, setPomo,
    scratch, setScratch,
    pinned, togglePin, isPinned,
    customizing, setCustomizing,
    addOpen, setAddOpen,
    recent, recordUse,
    route, setRoute,
    cmdOpen, setCmdOpen,
    now,
  };
}

function playBell() {
  try {
    const Ctx = window.AudioContext || window.webkitAudioContext;
    if (!Ctx) return;
    const ctx = new Ctx();
    const now = ctx.currentTime;
    const osc = ctx.createOscillator();
    const gain = ctx.createGain();
    osc.type = "sine";
    osc.frequency.setValueAtTime(880, now);
    osc.frequency.exponentialRampToValueAtTime(440, now + 0.6);
    gain.gain.setValueAtTime(0.0001, now);
    gain.gain.exponentialRampToValueAtTime(0.25, now + 0.02);
    gain.gain.exponentialRampToValueAtTime(0.0001, now + 0.8);
    osc.connect(gain).connect(ctx.destination);
    osc.start(now); osc.stop(now + 0.85);
    setTimeout(() => ctx.close(), 1200);
  } catch (e) {}
}

/* ============================================================
   LOGO
   ============================================================ */
function LogoMark() {
  return (
    <div className="logo-mark" aria-hidden="true">
      <div className="ring"></div>
      <div className="core"><span>OS</span></div>
    </div>
  );
}

/* ============================================================
   SIDEBAR
   ============================================================ */
function Sidebar() {
  const app = useApp();
  const isMac = useMemo(() => /Mac|iPhone|iPad/.test(navigator.platform), []);
  const focusActive = app.pomo.running && app.pomo.mode === "focus";

  return (
    <aside className="sidebar">
      <div className="sb-brand">
        <LogoMark />
        <div className="brand-text">
          <span className="brand-name">Office Sidekick</span>
          <span className="brand-by">by · vibeprosoft</span>
        </div>
      </div>

      <button className="sb-search" onClick={() => app.setCmdOpen(true)}>
        <span style={{ fontSize: 13 }}>🔍</span>
        <span>Search tools…</span>
        <span className="kbd">{isMac ? "⌘K" : "Ctrl K"}</span>
      </button>

      <div className="sb-section">
        <button className={"sb-item " + (app.route === "dashboard" ? "active" : "")} onClick={() => app.setRoute("dashboard")}>
          <span className="ic">⌂</span>
          <span>Dashboard</span>
        </button>
      </div>

      {CATEGORIES.map(cat => {
        const list = TOOLS.filter(t => t.cat === cat.id);
        if (list.length === 0) return null;
        return (
          <div className="sb-section" key={cat.id}>
            <h4>{cat.label}</h4>
            {list.map(tool => (
              <button
                key={tool.id}
                className={"sb-item " + (app.route === tool.id ? "active" : "")}
                onClick={() => app.setRoute(tool.id)}
              >
                <span className="ic">{tool.icon}</span>
                <span>{tool.name}</span>
                {tool.id === "pomodoro" && focusActive && (
                  <span className="badge">{fmtMs(app.pomo.remainingMs)}</span>
                )}
                {tool.isNew && tool.id !== "pomodoro" && <span className="badge" style={{ color: "var(--vps-blue-300)", background: "rgba(37,99,235,0.10)", borderColor: "rgba(96,165,250,0.30)" }}>new</span>}
              </button>
            ))}
          </div>
        );
      })}

      <div className="sb-foot">
        <button className="privacy-chip" onClick={() => app.setRoute("about")}>
          <span className="dot"></span>
          <span>In-browser · zero account</span>
          <span style={{ marginLeft: "auto", opacity: 0.6 }}>→</span>
        </button>
        <div className="vps-lockup">
          <img src="vibeprosoft-logo.png" alt="VibeProSoft" onError={(e) => e.target.style.display = 'none'} />
          <span>v3.1 · 2026</span>
        </div>
      </div>
    </aside>
  );
}

function fmtMs(ms) {
  const total = Math.max(0, Math.ceil(ms / 1000));
  const m = String(Math.floor(total / 60)).padStart(2, "0");
  const s = String(total % 60).padStart(2, "0");
  return `${m}:${s}`;
}

/* ============================================================
   TOP BAR
   ============================================================ */
function TopBar({ theme, setTheme }) {
  const app = useApp();
  const tool = TOOL_BY_ID[app.route];
  const title = app.route === "dashboard" ? "Dashboard"
              : app.route === "about" ? "About"
              : tool ? tool.name : app.route;

  return (
    <div className="topbar">
      <div className="crumb">
        <span>Office Sidekick</span>
        <span className="sep">/</span>
        <span className="cur">{title}</span>
      </div>
      <div className="spacer"></div>
      <div className="topbar-right">
        {app.route === "dashboard" && (
          <button
            className={"icon-btn " + (app.customizing ? "active" : "")}
            title={app.customizing ? "Done customizing" : "Customize dashboard"}
            onClick={() => app.setCustomizing(c => !c)}
          >
            {app.customizing ? "✓" : "⚙"}
          </button>
        )}
        {app.route !== "dashboard" && (
          <button className="icon-btn" title="Back to dashboard" onClick={() => app.setRoute("dashboard")}>
            ⌂
          </button>
        )}
        <button className="icon-btn" title="Toggle theme" onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
          {theme === "dark" ? "🌙" : "☀️"}
        </button>
        <button className="icon-btn" title="Search (⌘K)" onClick={() => app.setCmdOpen(true)}>
          🔍
        </button>
      </div>
    </div>
  );
}

/* ============================================================
   ROOT APP
   ============================================================ */
function App() {
  const state = useAppState();
  const [theme, setTheme] = useState(() => document.documentElement.getAttribute("data-theme") || "dark");

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

  useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        state.setCmdOpen(o => !o);
      } else if (e.key === "Escape") {
        if (state.cmdOpen) state.setCmdOpen(false);
        if (state.addOpen) state.setAddOpen(false);
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [state.cmdOpen, state.addOpen]);

  const Dashboard = window.Dashboard;
  const CommandPalette = window.CommandPalette;
  const AddWidgetPicker = window.AddWidgetPicker;

  const view = useMemo(() => {
    if (state.route === "dashboard") return <Dashboard />;
    if (state.route === "about") return <AboutView />;
    const tool = TOOL_BY_ID[state.route];
    if (!tool) return <Dashboard />;
    return <ToolView tool={tool} />;
  }, [state.route]);

  return (
    <AppCtx.Provider value={state}>
      <div className="bg-fx"></div>
      <div className="app">
        <Sidebar />
        <main className="main">
          <TopBar theme={theme} setTheme={setTheme} />
          {view}
        </main>
      </div>
      {state.cmdOpen && <CommandPalette onClose={() => state.setCmdOpen(false)} />}
      {state.addOpen && AddWidgetPicker && <AddWidgetPicker onClose={() => state.setAddOpen(false)} />}
    </AppCtx.Provider>
  );
}

/* ============================================================
   TOOL VIEW SHELL
   ============================================================ */
function ToolView({ tool }) {
  const app = useApp();
  const Comp = window.ToolComponents[tool.id];
  const pinned = app.isPinned(tool.id);
  return (
    <div className="tool-shell">
      <div className="tool-head">
        <div className="tool-icon">{tool.icon}</div>
        <div className="tool-title">
          <h1>{tool.name}</h1>
          <p>{tool.desc}</p>
        </div>
        <div className="spacer"></div>
        <button
          className={"pin-btn " + (pinned ? "pinned" : "")}
          onClick={() => app.togglePin(tool.id)}
          title={pinned ? "Remove from dashboard" : "Pin to dashboard"}
        >
          <span className="pin-ic">{pinned ? "✓" : "+"}</span>
          <span>{pinned ? "On dashboard" : "Add to dashboard"}</span>
        </button>
      </div>
      {Comp ? <Comp /> : <div className="card"><p className="muted">Tool not loaded.</p></div>}
    </div>
  );
}

/* ============================================================
   ABOUT VIEW
   ============================================================ */
function AboutView() {
  return (
    <div className="tool-shell">
      <div className="tool-head">
        <div className="tool-icon">🛡️</div>
        <div className="tool-title">
          <h1>How Office Sidekick works</h1>
          <p>A small pile of single-purpose tools that load fast and forget you when you close the tab. No accounts, no uploads of your work.</p>
        </div>
      </div>

      <div className="about-grid">
        <div className="about-card">
          <div className="ic">🛰️</div>
          <h3>Mostly static</h3>
          <p>The interface is plain HTML, CSS, and JavaScript served from the edge. The tools that need live data (Weather, FX, Crypto, Watercooler) call public APIs directly from your browser — we don't proxy or log them.</p>
        </div>
        <div className="about-card">
          <div className="ic">🔒</div>
          <h3>No accounts</h3>
          <p>Nothing to sign up for. Nothing follows you between devices. Open a tab, use a tool, close the tab.</p>
        </div>
        <div className="about-card">
          <div className="ic">👁️</div>
          <h3>No telemetry</h3>
          <p>Zero analytics, no pixels, no fingerprinting. The source is small enough to read in an afternoon.</p>
        </div>
        <div className="about-card">
          <div className="ic">🍪</div>
          <h3>Zero storage</h3>
          <p>No cookies, no localStorage. Your notes, timer settings, pinned widgets — all session-only. Close the tab, leave nothing behind.</p>
        </div>
      </div>

      <div className="card" style={{ marginTop: 8 }}>
        <h3 style={{ margin: "0 0 8px", fontSize: 14 }}>Why session-only</h3>
        <p className="sub" style={{ lineHeight: 1.6 }}>
          Saving your stuff means somewhere to store it, accounts to protect it, breach notifications to write. We
          decided we'd rather just not have any of that. If a tool feels like it needs persistence, hit <b>Copy</b> and
          paste somewhere safer.
        </p>
        <p className="sub" style={{ lineHeight: 1.6, marginTop: 8 }}>
          Questions? <b style={{ color: "var(--vps-blue-300)" }}>contact@vibeprosoft.com</b>
        </p>
      </div>
    </div>
  );
}

/* ============================================================
   MOUNT
   ============================================================ */
window.Office = { TOOLS, CATEGORIES, TOOL_BY_ID, useApp, fmtMs, AppCtx };
window.OfficeMountApp = () => {
  const root = ReactDOM.createRoot(document.getElementById("root"));
  root.render(<App />);
};
