/* app.jsx — shell, navigation, topbar, operator picker */

const NAV = [
  { id: "live",      label: "Live",      icon: "gauge" },
  { id: "checklist", label: "Checklist", icon: "clipboard" },
  { id: "report",    label: "Report",    icon: "report" },
  { id: "trends",    label: "Trends",    icon: "trend" },
  { id: "devices",   label: "Devices",   icon: "speaker" },
];

const SURFACES = {
  midnight: { "--bg-0": "#080b11", "--bg-1": "#0d121b", "--bg-2": "#121927", "--bg-3": "#182232", "--bg-rail": "#0a0e16" },
  charcoal: { "--bg-0": "#0e0e10", "--bg-1": "#161618", "--bg-2": "#1e1e22", "--bg-3": "#27272d", "--bg-rail": "#101012" },
  slate:    { "--bg-0": "#0b1119", "--bg-1": "#111a26", "--bg-2": "#172333", "--bg-3": "#1f2e42", "--bg-rail": "#0c1320" },
};

const TWEAK_DEFAULTS = {
  accent: "#4f7cff",
  surface: "midnight",
  gradeMode: "temperature",
  density: "regular",
};

function applyTheme(t) {
  const root = document.documentElement.style;
  Object.entries(SURFACES[t.surface] || SURFACES.midnight).forEach(([k, v]) => root.setProperty(k, v));
  root.setProperty("--accent", t.accent);
  // grade low color
  const low = t.gradeMode === "severity" ? "#d8a017" : "#58a6ff";
  root.setProperty("--grade-low", low);
  root.setProperty("--grade-low-bg", `color-mix(in srgb, ${low} 14%, transparent)`);
  const fs = { compact: 13, regular: 14, comfy: 15 }[t.density] || 14;
  document.documentElement.style.setProperty("font-size", fs + "px");
}

function useTweaks(defaults) {
  const [values, setValues] = React.useState(defaults);
  const setTweak = React.useCallback((key, val) => {
    setValues(prev => ({ ...prev, [key]: val }));
  }, []);
  return [values, setTweak];
}

function OperatorPicker() {
  const { operators, operator, setOperator, addOperator } = useQA();
  const [open, setOpen] = React.useState(false);
  const [adding, setAdding] = React.useState(false);
  const [name, setName] = React.useState("");
  const ref = React.useRef(null);

  React.useEffect(() => {
    if (!open) return;
    const onDoc = e => { if (ref.current && !ref.current.contains(e.target)) { setOpen(false); setAdding(false); } };
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, [open]);

  const submit = () => {
    if (name.trim()) { addOperator(name); setName(""); setAdding(false); setOpen(false); }
  };

  return (
    <div className="op-picker" ref={ref}>
      <button className="sess-switch" onClick={() => setOpen(o => !o)}>
        <Icon name="user" size={16} color="var(--fg-3)" />
        <span style={{ fontWeight: 700, fontSize: 13 }}>{operator || "Add person"}</span>
        <Icon name="chevron" size={14} color="var(--fg-3)" />
      </button>
      {open && (
        <div className="op-menu fade-up">
          <div className="op-menu-label">Operator on duty</div>
          {operators.length === 0
            ? <div className="op-empty">No people saved yet</div>
            : operators.map(o => (
              <button key={o} className={"op-item" + (o === operator ? " active" : "")} onClick={() => { setOperator(o); setOpen(false); }}>
                <Icon name="user" size={15} color={o === operator ? "var(--accent)" : "var(--fg-3)"} />
                <span style={{ flex: 1 }}>{o}</span>
                {o === operator && <Icon name="check" size={15} color="var(--accent)" />}
              </button>
            ))}
          <div className="op-divider" />
          {adding ? (
            <div className="op-add">
              <input className="op-input" autoFocus value={name} placeholder="Operator name"
                onChange={e => setName(e.target.value)}
                onKeyDown={e => { if (e.key === "Enter") submit(); if (e.key === "Escape") setAdding(false); }} />
              <button className="btn primary sm" onClick={submit}>Add</button>
            </div>
          ) : (
            <button className="op-item add" onClick={() => setAdding(true)}>
              <span className="op-plus">+</span><span>Add operator…</span>
            </button>
          )}
        </div>
      )}
    </div>
  );
}

function AddSundayButton() {
  const { sessions, addSunday, operator } = useQA();
  const [open, setOpen] = React.useState(false);
  const [date, setDate] = React.useState(() => window.nextSundayIso(sessions[sessions.length - 1]?.date));
  const [person, setPerson] = React.useState(operator || "");
  const ref = React.useRef(null);

  React.useEffect(() => {
    if (!open) return;
    const onDoc = e => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, [open]);

  React.useEffect(() => {
    if (open) {
      setDate(window.nextSundayIso(sessions[sessions.length - 1]?.date));
      setPerson(operator || "");
    }
  }, [open]);

  const submit = () => {
    addSunday(date, person);
    setOpen(false);
  };

  return (
    <div className="op-picker" ref={ref}>
      <button className="btn ghost" onClick={() => setOpen(o => !o)}><Icon name="calendar" size={15} />New Sunday</button>
      {open && (
        <div className="op-menu sunday-menu fade-up">
          <div className="op-menu-label">Add Sunday</div>
          <div className="op-add stacked">
            <input className="op-input" type="date" value={date} onChange={e => setDate(e.target.value)} />
            <input className="op-input" value={person} placeholder="Person name" onChange={e => setPerson(e.target.value)}
              onKeyDown={e => { if (e.key === "Enter") submit(); if (e.key === "Escape") setOpen(false); }} />
            <button className="btn primary sm" onClick={submit}>Add Sunday</button>
          </div>
        </div>
      )}
    </div>
  );
}

function Topbar({ view }) {
  const { viewDate, setViewDate, isCurrent, sessionHistory } = useQA();
  const subtitle = {
    live:      "Real-time speaker telemetry",
    checklist: "Run start/stop tests · auto-graded",
    report:    "End-to-end session report",
    trends:    "Week-over-week performance",
    devices:   "Auto-detected audio hardware",
  }[view];

  return (
    <div className="topbar">
      <div className="topbar-id">
        <div className="rail-logo" style={{ width: 42, height: 42, margin: 0 }}>
          <Icon name="waveform" size={22} color="var(--accent)" />
        </div>
        <div className="topbar-title">
          <h1>RLWC Live Audio Test</h1>
          <div className="topbar-sub">{subtitle}</div>
        </div>
      </div>
      <div className="spacer" />
      <div className="row gap-sm" style={{ padding: "0 22px" }}>
        {!isCurrent && <span className="tag medium">Saved Sunday</span>}
        <OperatorPicker />
        <AddSundayButton />
        <div className="sess-switch">
          <Icon name="calendar" size={16} color="var(--fg-3)" />
          <select value={viewDate} onChange={e => setViewDate(e.target.value)}
            style={{ background: "transparent", border: "none", color: "var(--fg-1)", fontWeight: 700, fontSize: 13, fontFamily: "var(--font)", cursor: "pointer", outline: "none" }}>
            {[...sessionHistory].reverse().map(h => (
              <option key={h.date} value={h.date} style={{ background: "var(--bg-2)" }}>
                Sunday Service · {window.fmtDate(h.date, { month: "short", day: "numeric" })}{h.current ? " (live)" : ""}
              </option>
            ))}
          </select>
        </div>
        <span className="row gap-sm" style={{ fontSize: 12, fontWeight: 700, letterSpacing: ".04em", color: "var(--fg-2)" }}>
          <span style={{
            width: 8, height: 8, borderRadius: 999,
            background: isCurrent ? "var(--c-mid)" : "var(--fg-3)",
            boxShadow: isCurrent ? "0 0 8px var(--c-mid)" : "none"
          }} />
          {isCurrent ? "CONNECTED" : "SAVED"}
        </span>
      </div>
    </div>
  );
}

function Rail({ view, setView }) {
  return (
    <nav className="rail">
      <div className="rail-logo"><Icon name="waveform" size={24} color="var(--accent)" /></div>
      <div className="rail-nav">
        {NAV.map(n => (
          <button key={n.id} className={"rail-item" + (view === n.id ? " active" : "")} onClick={() => setView(n.id)}>
            <Icon name={n.icon} size={21} />
            {n.label}
          </button>
        ))}
      </div>
      <div className="rail-spacer" />
      <button className={"rail-item" + (view === "devices" ? " active" : "")} onClick={() => setView("devices")}>
        <Icon name="settings" size={21} />Setup
      </button>
    </nav>
  );
}

function ChecklistGuard() {
  return <ChecklistView />;
}

function Shell() {
  const [view, setView] = React.useState("live");
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  React.useEffect(() => { applyTheme(t); }, [t]);
  const scrollRef = React.useRef(null);
  React.useEffect(() => { if (scrollRef.current) scrollRef.current.scrollTop = 0; }, [view]);

  return (
    <div className="app">
      <Rail view={view} setView={setView} />
      <div className="main">
        <Topbar view={view} />
        <div className="scroll" ref={scrollRef}>
          {view === "live"      && <LiveView />}
          {view === "checklist" && <ChecklistGuard />}
          {view === "report"    && <ReportView />}
          {view === "trends"    && <TrendsView />}
          {view === "devices"   && <DevicesView />}
        </div>
      </div>
      <AudioAccessPrompt setView={setView} />
    </div>
  );
}

function AudioAccessPrompt({ setView }) {
  const { deviceAccess, scanDevices, audioDevices } = useQA();
  const [dismissed, setDismissed] = React.useState(false);
  const shouldShow = !dismissed && (deviceAccess === "idle" || deviceAccess === "needs-permission" || deviceAccess === "blocked");
  if (!shouldShow) return null;

  return (
    <div className="access-backdrop">
      <div className="access-modal fade-up">
        <div className="rail-logo" style={{ margin: 0 }}><Icon name="speaker" size={24} color="var(--accent)" /></div>
        <div>
          <h2>Allow audio access</h2>
          <p>The browser will ask for microphone permission so RLWC Live Audio Test can analyze real audio from an input device. Speaker outputs can be listed, but browsers cannot record them directly without a loopback input.</p>
        </div>
        {deviceAccess === "blocked" && <div className="device-note"><Icon name="alert" size={16} color="var(--c-treble)" /><span>Permission is blocked. Enable microphone access for this site, then try again.</span></div>}
        <div className="row gap-sm">
          <button className="btn primary" onClick={() => scanDevices(true)}><Icon name="mic" size={15} />Allow access</button>
          <button className="btn ghost" onClick={() => { setDismissed(true); setView("devices"); }}>Devices</button>
        </div>
      </div>
    </div>
  );
}

function App() {
  return <QAProvider><Shell /></QAProvider>;
}

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