// zephyr-api.jsx — frontend client for /api/epics + author identity.
// Hooks: useAuthor, useEpics. Mutations: saveEpic, addEpic, deleteEpic.

const API_BASE = "/api";

// ── Author identity ─────────────────────────────────────────────────────────
const AUTHOR_KEY = "zephyr.author";
function getAuthor() {
  try { return localStorage.getItem(AUTHOR_KEY) || ""; }
  catch { return ""; }
}
function setAuthorStorage(name) {
  try { localStorage.setItem(AUTHOR_KEY, name); } catch {}
}

function useAuthor() {
  const [name, setName] = React.useState(() => getAuthor());
  const update = React.useCallback((n) => {
    const trimmed = (n || "").trim();
    setAuthorStorage(trimmed);
    setName(trimmed);
  }, []);
  return [name, update];
}

// ── Epic data hook ──────────────────────────────────────────────────────────
function useEpics() {
  const [epics, setEpics] = React.useState(null);   // null = loading
  const [error, setError] = React.useState(null);
  const [version, setVersion] = React.useState(0);  // bump to force reload

  React.useEffect(() => {
    let cancelled = false;
    setError(null);
    fetch(`${API_BASE}/epics`)
      .then(r => r.ok ? r.json() : Promise.reject(new Error(`HTTP ${r.status}`)))
      .then(data => { if (!cancelled) setEpics(data.epics || []); })
      .catch(err => { if (!cancelled) setError(err.message); });
    return () => { cancelled = true; };
  }, [version]);

  const reload = React.useCallback(() => setVersion(v => v + 1), []);

  // Optimistic update helpers
  const upsertLocal = React.useCallback((epic) => {
    setEpics(prev => {
      if (!prev) return prev;
      const idx = prev.findIndex(e => e.id === epic.id);
      if (idx >= 0) {
        const next = [...prev];
        next[idx] = { ...prev[idx], ...epic };
        return next;
      }
      return [...prev, epic];
    });
  }, []);

  const removeLocal = React.useCallback((id) => {
    setEpics(prev => prev ? prev.filter(e => e.id !== id) : prev);
  }, []);

  return { epics, error, reload, upsertLocal, removeLocal };
}

// ── Mutations ───────────────────────────────────────────────────────────────
async function saveEpic(epic, author) {
  const r = await fetch(`${API_BASE}/epics/${encodeURIComponent(epic.id)}`, {
    method: "PUT",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ ...epic, updated_by: author || "anon" }),
  });
  if (!r.ok) throw new Error(`Save failed: ${await r.text()}`);
  return r.json();
}

async function addEpic(epic, author) {
  const r = await fetch(`${API_BASE}/epics`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ ...epic, updated_by: author || "anon" }),
  });
  if (!r.ok) throw new Error(`Add failed: ${await r.text()}`);
  return r.json();
}

async function deleteEpic(id) {
  const r = await fetch(`${API_BASE}/epics/${encodeURIComponent(id)}`, { method: "DELETE" });
  if (!r.ok) throw new Error(`Delete failed: ${await r.text()}`);
  return r.json();
}

// ── Author modal (shown once, on first edit) ────────────────────────────────
function AuthorModal({ open, onSave, onCancel, initial = "" }) {
  const [name, setName] = React.useState(initial);
  React.useEffect(() => { if (open) setName(initial); }, [open, initial]);
  if (!open) return null;
  return (
    <div className="zr-modal-backdrop" onClick={onCancel}>
      <div className="zr-modal" onClick={e => e.stopPropagation()}>
        <div className="zr-modal-head">
          <span className="eb">Identify yourself</span>
          <h3>Who's making changes?</h3>
        </div>
        <p className="zr-modal-body">
          Your name appears next to edits so the team knows who changed what. Stored locally — no account needed.
        </p>
        <input
          className="zr-modal-input"
          autoFocus
          placeholder="e.g. John H, Tony, Drew"
          value={name}
          onChange={e => setName(e.target.value)}
          onKeyDown={e => {
            if (e.key === "Enter" && name.trim()) onSave(name.trim());
            if (e.key === "Escape") onCancel();
          }}
        />
        <div className="zr-modal-actions">
          <button className="zr-btn-ghost" onClick={onCancel}>Cancel</button>
          <button
            className="zr-btn-primary"
            disabled={!name.trim()}
            onClick={() => onSave(name.trim())}
          >Save</button>
        </div>
      </div>
    </div>
  );
}

// ── Loading state ───────────────────────────────────────────────────────────
function LoadingPanel({ error, onRetry }) {
  if (error) {
    return (
      <div className="zr-load-panel error">
        <span className="eb">Connection error</span>
        <h3>Couldn't load roadmap data.</h3>
        <code>{error}</code>
        <button className="zr-btn-primary" onClick={onRetry}>Retry</button>
      </div>
    );
  }
  return (
    <div className="zr-load-panel">
      <span className="eb">Loading</span>
      <h3>Fetching roadmap data…</h3>
      <div className="zr-load-bar"><div className="zr-load-bar-fill" /></div>
    </div>
  );
}

// Export to window for cross-script access
Object.assign(window, {
  ZephyrAPI: {
    useAuthor, useEpics, saveEpic, addEpic, deleteEpic,
    AuthorModal, LoadingPanel,
  }
});
