// data.jsx — Supabase-shaped mock data layer.
//
// Mirrors the intended schema:
//   clients (id, name, crm_type)
//   metrics (id, client_id, date, calls, form_fills, chats,
//            leads_generated, cases_signed, contracts_pending, contracts_lost)
//
// In production these would be `supabase.from('clients').select()` and
// `supabase.from('metrics').select().eq('client_id', id).gte('date', from)`.
// Here we synthesize deterministic per-period aggregates (plus a prior period
// for trend deltas) so the UI behaves exactly as it would against live data.

// ---- deterministic RNG (mulberry32) ---------------------------------------
function rng(seed) {
  let a = seed >>> 0;
  return function () {
    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;
  };
}
function hashStr(s) {
  let h = 2166136261;
  for (let i = 0; i < s.length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 16777619); }
  return h >>> 0;
}

// ---- clients table ---------------------------------------------------------
const CRM = ['Clio', 'MyCase', 'Filevine', 'Litify', 'PracticePanther', 'Smokeball'];

const CLIENTS = [
  { id: 'c01', name: 'Harlan & Webb Injury Law',        crm_type: 'Litify',          scale: 1.00, region: 'Atlanta, GA' },
  { id: 'c02', name: 'Castellano Trial Attorneys',      crm_type: 'Filevine',        scale: 1.45, region: 'Miami, FL' },
  { id: 'c03', name: 'Prairie State Disability Group',  crm_type: 'Clio',            scale: 0.62, region: 'Chicago, IL' },
  { id: 'c04', name: 'Okafor Immigration Partners',     crm_type: 'MyCase',          scale: 0.78, region: 'Houston, TX' },
  { id: 'c05', name: 'Vance Criminal Defense',          crm_type: 'PracticePanther', scale: 0.55, region: 'Denver, CO' },
  { id: 'c06', name: 'Sloane Family Law Collective',    crm_type: 'Smokeball',       scale: 0.71, region: 'Portland, OR' },
  { id: 'c07', name: 'Dominguez Workers Comp',          crm_type: 'Litify',          scale: 1.18, region: 'Phoenix, AZ' },
  { id: 'c08', name: 'Greenfield Estate & Probate',     crm_type: 'Clio',            scale: 0.49, region: 'Boston, MA' },
  { id: 'c09', name: 'North Star Mass Tort Group',      crm_type: 'Filevine',        scale: 1.92, region: 'Minneapolis, MN' },
  { id: 'c10', name: 'Reyes & Tan Employment Law',      crm_type: 'MyCase',          scale: 0.84, region: 'San Jose, CA' },
  { id: 'c11', name: 'Beaumont Auto Accident Firm',     crm_type: 'Litify',          scale: 1.33, region: 'Dallas, TX' },
  { id: 'c12', name: 'Kowalski Bankruptcy Advisors',    crm_type: 'PracticePanther', scale: 0.41, region: 'Cleveland, OH' },
  { id: 'c13', name: 'Aspen Medical Malpractice',       crm_type: 'Filevine',        scale: 0.96, region: 'Salt Lake City, UT' },
  { id: 'c14', name: 'Bridgewater Real Estate Law',     crm_type: 'Smokeball',       scale: 0.58, region: 'Charlotte, NC' },
  { id: 'c15', name: 'Quinn Veterans Benefits Law',     crm_type: 'MyCase',          scale: 0.67, region: 'Tampa, FL' },
];

// ---- period config ---------------------------------------------------------
const PERIODS = {
  weekly:  { label: 'Weekly',  mult: 6.8, range: 'This week · May 22 – 28' },
  monthly: { label: 'Monthly', mult: 29,  range: 'This month · May 2026' },
  annual:  { label: 'Annual',  mult: 330, range: 'Year to date · 2026' },
};
const PERIOD_KEYS = ['weekly', 'monthly', 'annual'];

// ---- metric synthesis ------------------------------------------------------
// Builds metrics for one client given a volume multiplier (1 = a single day)
// and a deterministic seed. `salt` shifts the seed so the "previous period"
// comes out close-but-different (drives trend arrows).
function buildRowMult(client, mult, seedKey, salt) {
  const r = rng(hashStr(client.id + seedKey + salt));
  const noise = (lo, hi) => lo + r() * (hi - lo);

  const base = client.scale * mult;
  const calls      = Math.max(0, Math.round(base * noise(2.1, 2.9)));
  const form_fills = Math.max(0, Math.round(base * noise(1.3, 1.9)));
  const chats      = Math.max(0, Math.round(base * noise(0.8, 1.4)));
  const leads_generated = calls + form_fills + chats;

  // Funnel: a share of leads convert to signed cases; the rest split into
  // pending and lost contracts.
  const signRate    = noise(0.16, 0.30);
  const cases_signed = Math.round(leads_generated * signRate);
  const remaining    = leads_generated - cases_signed;
  const contracts_pending = Math.round(remaining * noise(0.18, 0.34));
  const contracts_lost    = Math.round(remaining * noise(0.10, 0.22));

  return {
    calls, form_fills, chats, leads_generated,
    cases_signed, contracts_pending, contracts_lost,
  };
}

// Returns { ...metrics, prev: {...metrics} } for a client + named period.
function clientMetrics(client, periodKey) {
  const mult = PERIODS[periodKey].mult;
  const cur = buildRowMult(client, mult, periodKey, 'cur');
  const prev = buildRowMult(client, mult, periodKey, 'prev');
  return { ...cur, prev };
}

// Roll-up: sum every client's metrics for the period (incl. prev for trends).
function rollupMetrics(periodKey) {
  const keys = ['calls', 'form_fills', 'chats', 'leads_generated',
                'cases_signed', 'contracts_pending', 'contracts_lost'];
  const total = Object.fromEntries(keys.map(k => [k, 0]));
  const prev  = Object.fromEntries(keys.map(k => [k, 0]));
  const rows = CLIENTS.map(c => {
    const m = clientMetrics(c, periodKey);
    keys.forEach(k => { total[k] += m[k]; prev[k] += m.prev[k]; });
    return { client: c, ...m };
  });
  return { total: { ...total, prev }, rows };
}

// ---- custom date range -----------------------------------------------------
const DAY_MS = 86400000;
function parseISO(s) { const [y, m, d] = s.split('-').map(Number); return new Date(y, m - 1, d); }
function toISO(d) { return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; }
function dayCount(fromISO, toISO_) { return Math.round((parseISO(toISO_) - parseISO(fromISO)) / DAY_MS) + 1; }

// Metrics for an arbitrary [from, to] range. Volume scales with the number of
// days; the previous period is the equally-long range immediately before.
function clientMetricsRange(client, fromISO, toISO_) {
  const days = Math.max(1, dayCount(fromISO, toISO_));
  const seedKey = 'range:' + fromISO + ':' + toISO_;
  const cur  = buildRowMult(client, days, seedKey, 'cur');
  const prev = buildRowMult(client, days, seedKey, 'prev');
  return { ...cur, prev };
}

function rollupMetricsRange(fromISO, toISO_) {
  const keys = ['calls', 'form_fills', 'chats', 'leads_generated',
                'cases_signed', 'contracts_pending', 'contracts_lost'];
  const total = Object.fromEntries(keys.map(k => [k, 0]));
  const prev  = Object.fromEntries(keys.map(k => [k, 0]));
  const rows = CLIENTS.map(c => {
    const m = clientMetricsRange(c, fromISO, toISO_);
    keys.forEach(k => { total[k] += m[k]; prev[k] += m.prev[k]; });
    return { client: c, ...m };
  });
  return { total: { ...total, prev }, rows };
}

const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
function fmtRange(fromISO, toISO_) {
  const a = parseISO(fromISO), b = parseISO(toISO_);
  const sameYear = a.getFullYear() === b.getFullYear();
  const left = `${MONTHS[a.getMonth()]} ${a.getDate()}${sameYear ? '' : ', ' + a.getFullYear()}`;
  const right = `${MONTHS[b.getMonth()]} ${b.getDate()}, ${b.getFullYear()}`;
  if (fromISO === toISO_) return right;
  return `${left} – ${right}`;
}

// Percent change vs prior period. Returns { pct, dir } where dir ∈ -1|0|1.
function trend(cur, prev) {
  if (prev === 0) return { pct: cur === 0 ? 0 : 100, dir: cur === 0 ? 0 : 1 };
  const pct = ((cur - prev) / prev) * 100;
  return { pct: Math.abs(pct), dir: pct > 0.5 ? 1 : pct < -0.5 ? -1 : 0 };
}

function getClient(id) { return CLIENTS.find(c => c.id === id); }

Object.assign(window, {
  CLIENTS, CRM, PERIODS, PERIOD_KEYS,
  clientMetrics, rollupMetrics, trend, getClient,
  clientMetricsRange, rollupMetricsRange, fmtRange, toISO, parseISO, dayCount, MONTHS,
});
