// Quizrs — data layer.
// Replaces the prototype's mock-data module. Talks to the SAME Cloudflare Worker
// backend the classic app uses (window.quizrsAuth + /v1/* + /api/public/*), so the
// new and classic UIs are fully cross-compatible. No backend changes.

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

const StoreContext = createContext(null);
function useStore() { return useContext(StoreContext); }

// ── visuals: deterministic tint + glyph per quiz, since the backend has no theme ──
const TINT_KEYS = ["indigo", "green", "coral", "blue", "plum", "amber", "teal", "slate"];
const GLYPHS = ["zap", "sparkle", "globe", "flag", "trophy", "star", "edit", "stats"];
function hashStr(s) { let h = 0; for (const c of String(s)) h = (h * 31 + c.charCodeAt(0)) >>> 0; return h; }
function visualFor(id) {
  const h = hashStr(id || "q");
  return { tint: TINT_KEYS[h % TINT_KEYS.length], glyph: GLYPHS[(h >> 3) % GLYPHS.length] };
}

function relTime(iso) {
  if (!iso) return "—";
  const then = new Date(iso).getTime();
  if (!Number.isFinite(then)) return "—";
  const s = Math.max(1, Math.round((Date.now() - then) / 1000));
  if (s < 60) return "just now";
  const m = Math.round(s / 60); if (m < 60) return m + "m ago";
  const h = Math.round(m / 60); if (h < 24) return h + "h ago";
  const d = Math.round(h / 24); if (d < 7) return d + "d ago";
  const w = Math.round(d / 7); if (w < 5) return w + "w ago";
  return new Date(iso).toLocaleDateString(undefined, { month: "short", day: "numeric" });
}

// Backend question shape {id, q, options[4], correct} → UI shape {q, opts, correct, type}.
function mapQuestions(questions, contentType) {
  return (Array.isArray(questions) ? questions : []).map((q) => ({
    id: q.id,
    q: q.q || q.question || q.prompt || "",
    opts: Array.isArray(q.opts) ? q.opts : Array.isArray(q.options) ? q.options : [],
    correct: contentType === "poll" ? null : (q.correct ?? null),
    type: contentType === "poll" ? "Poll" : "Multiple choice",
  }));
}

// Normalize a backend quiz record (list row or full quiz) into the shape the
// new UI screens consume.
function normalizeQuiz(record, collections) {
  if (!record) return null;
  const id = record.id || record.quizId || record.publicId;
  const contentType = record.contentType || record.type || "quiz";
  const isPoll = contentType === "poll";
  const publishState = record.publishState || record.publish_state || (record.published ? "published" : "draft");
  const analytics = record.analytics || null;
  const submissionCount = Number(record.submissionCount ?? analytics?.submissionCount ?? 0);
  const completionCount = Number(record.completionCount ?? analytics?.completionCount ?? 0);
  const v = visualFor(id);
  const questions = mapQuestions(record.questions, contentType);
  return {
    id,
    publicId: record.publicId || record.public_id || null,
    title: record.title || "Untitled quiz",
    contentType,
    isPoll,
    subject: isPoll ? "Poll" : "Quiz",
    difficulty: record.difficulty || null,
    sourceInputPreview: record.sourceInputPreview || record.source_input_preview || "",
    questionCount: Number(record.questionCount ?? questions.length ?? 0),
    questions,
    status: publishState === "published" ? "live" : "draft",
    publishState,
    responseCollectionMode:
      record.responseCollectionMode ||
      record.settings?.responseCollectionMode ||
      "off",
    submissionCount,
    completionCount,
    plays: submissionCount,
    createdAt: record.createdAt || record.created_at || null,
    updatedAt: record.updatedAt || record.updated_at || record.createdAt || null,
    updated: relTime(record.updatedAt || record.updated_at || record.createdAt),
    folder: (collections && collections[id]) || null,
    tint: v.tint,
    glyph: v.glyph,
    raw: record,
  };
}

// ── collections (client-side, localStorage; no backend schema change) ──
const COLL_KEY = "quizlab.collections.v1";
function loadCollections() {
  try { return JSON.parse(localStorage.getItem(COLL_KEY) || "{}"); } catch { return {}; }
}
function saveCollections(map) {
  try { localStorage.setItem(COLL_KEY, JSON.stringify(map)); } catch {}
}

// ── theme / appearance settings (localStorage) ──
const SETTINGS_KEY = "quizlab.settings.v1";
const SETTINGS_DEFAULTS = { accent: "#4f46e5", theme: "light", density: "comfy", radius: 12 };
const ACCENTS = {
  "#4f46e5": { ink: "#3730a3", tint: "#eef0ff" },
  "#0d9488": { ink: "#0a6b62", tint: "#e1f3f1" },
  "#d97757": { ink: "#a04e2c", tint: "#fbeae3" },
  "#db2777": { ink: "#9d174d", tint: "#fce7f0" },
  "#2563eb": { ink: "#1e40af", tint: "#e7efff" },
  "#16a34a": { ink: "#15803d", tint: "#e6f6ec" },
};
function loadSettings() {
  try { return { ...SETTINGS_DEFAULTS, ...JSON.parse(localStorage.getItem(SETTINGS_KEY) || "{}") }; }
  catch { return { ...SETTINGS_DEFAULTS }; }
}

function applyUsage(usage, fallback) {
  if (!usage) return fallback || null;
  const quizzesUsed = Number(
    usage.quizzesUsed ?? usage.quotaUsed ?? usage.used ?? usage.count ?? usage.usageCount ?? fallback?.quizzesUsed ?? 0
  );
  const limitRaw = usage.quotaLimit ?? usage.limit ?? usage.monthlyLimit ?? fallback?.quotaLimit ?? null;
  const quotaLimit = limitRaw === null || limitRaw === undefined || limitRaw === "" ? null : Number(limitRaw);
  return { ...usage, plan: usage.plan || fallback?.plan || "free", quizzesUsed, quotaLimit };
}

function StoreProvider({ children }) {
  const [authReady, setAuthReady] = useState(false);
  const [authIssue, setAuthIssue] = useState("");
  const [backendIssue, setBackendIssue] = useState("");
  const [user, setUser] = useState(null);
  const [apiBase, setApiBase] = useState("");
  const [siteUrl, setSiteUrl] = useState(typeof window !== "undefined" ? window.location.origin : "");
  const [quizzes, setQuizzes] = useState([]);
  const [usage, setUsage] = useState(null);
  const [libraryLoading, setLibraryLoading] = useState(false);
  const [collections, setCollections] = useState(loadCollections);
  const [settings, setSettings] = useState(loadSettings);
  const collectionsRef = useRef(collections);
  collectionsRef.current = collections;

  // ── apply appearance settings as CSS vars ──
  useEffect(() => {
    const a = ACCENTS[settings.accent] || ACCENTS["#4f46e5"];
    const r = document.documentElement;
    r.style.setProperty("--accent", settings.accent);
    r.style.setProperty("--accent-ink", a.ink);
    r.style.setProperty("--accent-tint", a.tint);
    r.setAttribute("data-theme", settings.theme);
    r.style.setProperty("--space", settings.density === "compact" ? "0.82" : "1");
    r.style.setProperty("--r", settings.radius + "px");
    try { localStorage.setItem(SETTINGS_KEY, JSON.stringify(settings)); } catch {}
  }, [settings]);

  const setSetting = useCallback((key, val) => setSettings((s) => ({ ...s, [key]: val })), []);

  // ── api ──
  const fetchApi = useCallback(async (path, options = {}) => {
    const base = apiBase || window.quizrsAuth?.getApiBase?.();
    if (!base) throw new Error("Cloudflare API base is not configured.");
    const headers = new Headers(options.headers || {});
    headers.set("Accept", "application/json");
    const token = await window.quizrsAuth?.getSessionToken?.();
    if (token) headers.set("Authorization", `Bearer ${token}`);
    const response = await fetch(`${base.replace(/\/+$/, "")}${path}`, { ...options, headers });
    const payload = await response.json().catch(() => ({}));
    if (!response.ok) throw new Error(payload.error || payload.message || `Request failed for ${path}`);
    return payload;
  }, [apiBase]);

  const loadLibrary = useCallback(async () => {
    setLibraryLoading(true);
    try {
      const [quizRes, usageRes] = await Promise.allSettled([
        fetchApi("/v1/me/quizzes"),
        fetchApi("/v1/me/usage"),
      ]);
      if (quizRes.status === "fulfilled") {
        const items = quizRes.value.quizzes || quizRes.value.items || quizRes.value.data || [];
        setQuizzes((Array.isArray(items) ? items : []).map((q) => normalizeQuiz(q, collectionsRef.current)).filter(Boolean));
      } else {
        setBackendIssue(quizRes.reason?.message || "Failed to load quizzes.");
      }
      if (usageRes.status === "fulfilled") {
        setUsage((prev) => applyUsage(usageRes.value.usage || usageRes.value.data || usageRes.value, prev));
      }
    } finally {
      setLibraryLoading(false);
    }
  }, [fetchApi]);

  // ── auth bootstrap (mirrors classic app.html init/applyAuthSnapshot) ──
  useEffect(() => {
    const auth = window.quizrsAuth;
    if (!auth) {
      setAuthReady(true);
      setAuthIssue("The shared auth helper failed to load.");
      return;
    }
    let active = true;
    const apply = (snapshot) => {
      if (!snapshot?.ready) return;
      setAuthReady(true);
      if (!snapshot.configured) { setAuthIssue(snapshot.error || "Clerk is not configured."); setUser(null); return; }
      if (snapshot.error && !snapshot.isSignedIn) { setAuthIssue(snapshot.error); setUser(null); return; }
      if (!snapshot.isSignedIn || !snapshot.user) {
        setAuthIssue("");
        setUser(null);
        auth.redirectToSignIn?.(window.location.pathname + window.location.search);
        return;
      }
      setAuthIssue("");
      const u = snapshot.user;
      setUser({
        id: u.id,
        name: u.fullName || u.name || [u.firstName, u.lastName].filter(Boolean).join(" ") || u.username || (u.email || "").split("@")[0] || "You",
        email: u.email || u.primaryEmailAddress || "",
        imageUrl: u.imageUrl || u.image || null,
        plan: u.plan || "free",
        quotaLimit: u.quotaLimit ?? null,
        quizzesUsed: u.quizzesUsed ?? 0,
      });
    };
    auth.ready().then(() => {
      if (!active) return;
      const config = auth.getPublicConfig?.() || {};
      setApiBase(config.cloudflareApiBase || "");
      setSiteUrl(config.cloudflarePublicBaseUrl || config.appUrl || window.location.origin);
      if (!config.cloudflareApiBase) {
        setBackendIssue("Set `CLOUDFLARE_API_BASE` (or `CLOUDFLARE_WORKER_URL`) so this app can reach the Worker.");
      }
      apply(auth.getSnapshot());
    }).catch((e) => { setAuthReady(true); setAuthIssue(e.message || "Failed to load auth."); });
    auth.onChange?.(apply);
    return () => { active = false; };
  }, []);

  // Load library once we have a signed-in user + api base.
  useEffect(() => {
    if (user && apiBase) loadLibrary();
  }, [user?.id, apiBase, loadLibrary]);

  // ── actions ──
  const generate = useCallback(async ({ inputText, mode = "topic", contentType = "quiz", questionCount = 8, difficulty = "medium" }) => {
    const payload = { inputText: String(inputText || "").trim(), mode, contentType, questionCount: Number(questionCount), difficulty: contentType === "poll" ? null : difficulty };
    const res = await fetchApi("/v1/quizzes/generate", {
      method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload),
    });
    if (res.usage) setUsage((prev) => applyUsage(res.usage, prev));
    const quiz = normalizeQuiz(res.quiz || res.quizRecord || res.data || res, collectionsRef.current);
    await loadLibrary();
    return quiz;
  }, [fetchApi, loadLibrary]);

  const getQuiz = useCallback(async (id) => {
    const res = await fetchApi(`/v1/quizzes/${encodeURIComponent(id)}`);
    return normalizeQuiz(res.quiz || res.data || res, collectionsRef.current);
  }, [fetchApi]);

  const getPublicQuiz = useCallback(async (idOrSlug) => {
    const res = await fetchApi(`/api/public/quizzes/${encodeURIComponent(idOrSlug)}`);
    return normalizeQuiz(res.quiz || res.data || res, collectionsRef.current);
  }, [fetchApi]);

  const publish = useCallback(async (id, published = true) => {
    const res = await fetchApi(`/v1/quizzes/${encodeURIComponent(id)}/publish`, {
      method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ published }),
    });
    const quiz = normalizeQuiz(res.quiz || res.data || res, collectionsRef.current);
    setQuizzes((list) => list.map((q) => (q.id === id ? quiz : q)));
    return quiz;
  }, [fetchApi]);

  const setResponseMode = useCallback(async (id, responseCollectionMode) => {
    const res = await fetchApi(`/v1/quizzes/${encodeURIComponent(id)}/settings`, {
      method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ responseCollectionMode }),
    });
    const quiz = normalizeQuiz(res.quiz || res.data || res, collectionsRef.current);
    setQuizzes((list) => list.map((q) => (q.id === id ? quiz : q)));
    return quiz;
  }, [fetchApi]);

  const getAnalytics = useCallback(async (id) => {
    const res = await fetchApi(`/v1/quizzes/${encodeURIComponent(id)}/analytics`);
    return res.analytics || res.data || res;
  }, [fetchApi]);

  // ── collections ──
  const setFolder = useCallback((id, folder) => {
    setCollections((prev) => {
      const next = { ...prev };
      if (folder) next[id] = folder; else delete next[id];
      saveCollections(next);
      return next;
    });
    setQuizzes((list) => list.map((q) => (q.id === id ? { ...q, folder: folder || null } : q)));
  }, []);

  const folders = useMemo(() => {
    const set = new Map();
    for (const q of quizzes) if (q.folder) set.set(q.folder, (set.get(q.folder) || 0) + 1);
    return Array.from(set, ([name, count]) => ({ name, count }));
  }, [quizzes]);

  const shareUrlFor = useCallback((q) => {
    const base = (siteUrl || "").replace(/\/+$/, "");
    const slug = q?.publicId || q?.id;
    return slug ? `${base}/q/${encodeURIComponent(slug)}` : "";
  }, [siteUrl]);

  const value = {
    authReady, authIssue, backendIssue, user, apiBase, siteUrl,
    quizzes, usage, libraryLoading,
    settings, setSetting, ACCENTS,
    collections, folders, setFolder,
    loadLibrary, generate, getQuiz, getPublicQuiz, publish, setResponseMode, getAnalytics, shareUrlFor,
    fetchApi,
  };

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

Object.assign(window, { StoreContext, useStore, StoreProvider, relTime, mapQuestions, normalizeQuiz, visualFor });
