// data.jsx — load static-data agents + deterministic fixed group assignment
// (derived from the agent list with a seeded PRNG — identical on every device)

// 14 safari groups (group #14 = แรด/RHINOS) — name + visuals for the reveal & namecard
const GROUPS = [
  { name: "สิงโต",     en: "LIONS",     emoji: "🦁", from: "#C49A5A", to: "#9c7836" },
  { name: "เสือ",      en: "TIGERS",    emoji: "🐯", from: "#C0430F", to: "#8a2e08" },
  { name: "ช้าง",      en: "ELEPHANTS", emoji: "🐘", from: "#8B5E2E", to: "#5f3f1e" },
  { name: "ยีราฟ",     en: "GIRAFFES",  emoji: "🦒", from: "#6B8C52", to: "#4d6b39" },
  { name: "ม้าลาย",    en: "ZEBRAS",    emoji: "🦓", from: "#3B2A1A", to: "#241910" },
  { name: "ฟลามิงโก",  en: "FLAMINGOS", emoji: "🦩", from: "#D98CA0", to: "#b05f74" },
  { name: "ฮิปโป",     en: "HIPPOS",    emoji: "🦛", from: "#7E7464", to: "#544c40" },
  { name: "อูฐ",       en: "CAMELS",    emoji: "🐪", from: "#D2A56B", to: "#a87c44" },
  { name: "กิ้งก่า",   en: "GECKOS",    emoji: "🦎", from: "#7FA05A", to: "#5c7a3d" },
  { name: "ลิง",       en: "MONKEYS",   emoji: "🐒", from: "#9C6B3E", to: "#6e4824" },
  { name: "เมียร์แคท", en: "MEERKATS",  emoji: "🦫", from: "#C9A06A", to: "#9c7644" },
  { name: "สล็อต",     en: "SLOTHS",    emoji: "🦥", from: "#8C7B5A", to: "#62543a" },
  { name: "วอมแบต",    en: "WOMBATS",   emoji: "🐹", from: "#A0734E", to: "#714c30" },
  { name: "แรด",       en: "RHINOS",    emoji: "🦏", from: "#6F6257", to: "#49403a" },
];

const GROUP_NAMES = GROUPS.map((g) => g.name);
const groupMeta = (name) => GROUPS.find((g) => g.name === name) || GROUPS[0];

// faculty from id prefix — CSA / CSB / CSC (anything else buckets to OTHER but is still assigned)
function facultyOf(id) {
  const m = /^(CSA|CSB|CSC)/.exec(id || "");
  return m ? m[1] : "OTHER";
}

// ── deterministic PRNG (seeded) ─────────────────────────────
// Group assignment must be identical on every device WITHOUT a backend, so we
// can't use Math.random()/localStorage (those differ per browser & per cache).
// Instead we seed a PRNG with a fixed constant + faculty and derive the whole
// assignment purely from the agent list — same input → same output everywhere.

// xmur3 string → 32-bit seed
function xmur3(str) {
  let h = 1779033703 ^ str.length;
  for (let i = 0; i < str.length; i++) {
    h = Math.imul(h ^ str.charCodeAt(i), 3432918353);
    h = (h << 13) | (h >>> 19);
  }
  return () => { h = Math.imul(h ^ (h >>> 16), 2246822507); h = Math.imul(h ^ (h >>> 13), 3266489909); return (h ^= h >>> 16) >>> 0; };
}

// mulberry32 PRNG from a numeric seed → floats in [0,1)
function mulberry32(a) {
  return () => {
    a |= 0; a = (a + 0x6d2b79f5) | 0;
    let t = Math.imul(a ^ (a >>> 15), 1 | a);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

// Fisher–Yates seeded by a string (deterministic — same seed → same order)
function seededShuffle(arr, seedStr) {
  const rand = mulberry32(xmur3(seedStr)());
  const a = arr.slice();
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(rand() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

const ASSIGN_SEED = "buddy-safari-2026"; // bump to reshuffle everyone

// Load every agent. Dynamic fetch when served over http(s); falls back to the
// pre-bundled window.AGENTS for file:// (browsers block fetch of local files).
async function fetchAgents() {
  try {
    const res = await fetch("src/static-data/all-agents.json");
    if (res.ok) {
      const d = await res.json();
      const list = Array.isArray(d) ? d : d.agents;
      if (Array.isArray(list) && list.length) return list;
    }
  } catch (e) { /* file:// or offline — use fallback below */ }
  if (Array.isArray(window.AGENTS) && window.AGENTS.length) return window.AGENTS;
  throw new Error("โหลดข้อมูล agents ไม่สำเร็จ");
}

// Build the FIXED assignment. Each faculty's ids are sorted (stable order),
// seed-shuffled with the SAME seed everywhere, then dealt round-robin across
// the 14 groups → even distribution AND identical on every device/browser.
// Derived purely from the agent list, so an agent always lands in the same
// group with no localStorage and no backend round-trip.
function loadAssignments(agents) {
  const byFac = {};
  agents.forEach((a) => { const f = facultyOf(a.id); (byFac[f] = byFac[f] || []).push(a.id); });

  const map = {};
  Object.keys(byFac).sort().forEach((f) => {
    const ids = byFac[f].slice().sort();                 // stable base order
    seededShuffle(ids, `${ASSIGN_SEED}:${f}`).forEach((id, i) => {
      map[id] = GROUP_NAMES[i % GROUP_NAMES.length];
    });
  });
  return map;
}

// One-shot loader, memoised on window so screens share the same data.
async function loadAppData() {
  if (window.__APPDATA__) return window.__APPDATA__;
  const agents = await fetchAgents();
  const assignments = loadAssignments(agents);
  const data = {
    agents, assignments,
    groups: GROUPS, groupNames: GROUP_NAMES, groupMeta,
    facultyOf, emojiOf: (g) => groupMeta(g).emoji,
  };
  window.__APPDATA__ = data;
  window.HERDS = GROUPS; // back-compat fallback for BuddyHint
  return data;
}

Object.assign(window, { loadAppData, GROUPS, GROUP_NAMES, groupMeta, facultyOf });
