/* Demo data loader for the Thesis prototype.

   Loads 9 relational JSON tables from data/, exposes them on window.db, and
   provides query helpers on window.dbq. Sparkline arrays are derived at load
   time from each candidate's sparkSeed so the JSON stays storage-shaped (no
   pre-computed display arrays).

   To swap to a real backend later: replace the fetch() calls with API calls
   that return the same row shapes. No screen component knows the source. */

function spark(seed, len = 24, vol = 0.08) {
  const out = [];
  let v = 0.5;
  for (let i = 0; i < len; i++) {
    const r = Math.sin(seed * (i + 1)) * 0.5 + Math.cos(seed * 0.7 * (i + 2)) * 0.5;
    v += r * vol + 0.005;
    v = Math.max(0.05, Math.min(0.95, v));
    out.push(v);
  }
  return out;
}

window.spark = spark;

const TABLES = [
  "profiles",
  "theses",
  "criteria",
  "anti_theses",
  "candidates",
  "candidate_scores",
  "candidate_anti_triggers",
  "news",
  "refinements",
];

window.DATA_READY = Promise.all(
  TABLES.map((name) =>
    fetch(`data/${name}.json`).then((r) => {
      if (!r.ok) throw new Error(`Failed to load data/${name}.json: ${r.status}`);
      return r.json();
    }).then((rows) => [name, rows])
  )
).then((entries) => {
  const db = Object.fromEntries(entries);

  // Derive sparkline arrays from seed; keep storage rows immutable in db.
  for (const c of db.candidates) {
    c.spark = spark(c.sparkSeed);
  }

  window.db = db;
  window.dbq = makeQueries(db);
});

function makeQueries(db) {
  const byProfile = (table) => (profileId) => db[table].filter((r) => r.profile_id === profileId);
  const byThesis  = (table) => (thesisId)  => db[table].filter((r) => r.thesis_id  === thesisId);
  const byCandidate = (table) => (candidateId) => db[table].filter((r) => r.candidate_id === candidateId);

  return {
    // Profiles
    profileById: (id) => db.profiles.find((p) => p.id === id),
    profileBySlug: (slug) => db.profiles.find((p) => p.slug === slug),
    allProfiles: () => db.profiles,

    // Theses
    thesesForProfile: byProfile("theses"),
    thesisById: (id) => db.theses.find((t) => t.id === id),
    thesisBySlug: (profileId, slug) => db.theses.find((t) => t.profile_id === profileId && t.slug === slug),

    // Criteria
    criteriaForProfile: byProfile("criteria"),
    criterionById: (id) => db.criteria.find((c) => c.id === id),

    // Anti-theses
    antiThesesForThesis: (thesisId) => byThesis("anti_theses")(thesisId).slice().sort((a, b) => a.position - b.position),

    // Candidates
    candidatesForProfile: byProfile("candidates"),
    candidatesForThesis: (thesisId) => byThesis("candidates")(thesisId).slice().sort((a, b) => a.rank - b.rank),
    candidateById: (id) => db.candidates.find((c) => c.id === id),
    candidateByTicker: (profileId, ticker) =>
      db.candidates.find((c) => c.profile_id === profileId && c.ticker === ticker),

    // Scores (per criterion)
    scoresForCandidate: byCandidate("candidate_scores"),
    scoresByCandidateCriterion: (candidateId, criterionId) =>
      db.candidate_scores.find((s) => s.candidate_id === candidateId && s.criterion_id === criterionId),

    // Anti-thesis triggers
    antiTriggersForCandidate: byCandidate("candidate_anti_triggers"),

    // News & refinements
    newsForProfile: (profileId) =>
      byProfile("news")(profileId).slice().sort((a, b) => a.position - b.position),
    refinementsForProfile: (profileId) =>
      byProfile("refinements")(profileId).slice().sort((a, b) => a.position - b.position),
  };
}
