// Seed data for the RecSports Hub demo.

const ROLES = {
  super_admin: { label: 'Super admin', color: 'gold' },
  staff_admin: { label: 'Staff admin', color: 'neutral' },
  cs_president: { label: 'CS president', color: 'neutral' },
  cs_helper: { label: 'CS helper', color: 'neutral' },
};

const USERS = [
  { id: 'u1', name: 'Justin Reilly', email: 'justin.reilly@ferris.edu', role: 'super_admin', lastLogin: '2026-05-14T08:12:00', status: 'Active', initials: 'JR' },
  { id: 'u2', name: 'Zac Holland', email: 'zac.holland@ferris.edu', role: 'super_admin', lastLogin: '2026-05-13T15:40:00', status: 'Active', initials: 'ZH' },
  { id: 'u3', name: 'Val Marquez', email: 'val.marquez@ferris.edu', role: 'staff_admin', domain: 'courts', lastLogin: '2026-05-14T07:55:00', status: 'Active', initials: 'VM' },
  { id: 'u4', name: 'Stoney Carter', email: 'stoney.carter@ferris.edu', role: 'staff_admin', domain: 'fields', lastLogin: '2026-05-14T09:02:00', status: 'Active', initials: 'SC' },
  { id: 'u5', name: 'Maya Brooks', email: 'maya.brooks@ferris.edu', role: 'cs_president', lastLogin: '2026-05-13T19:21:00', status: 'Active', initials: 'MB' },
  { id: 'u6', name: 'Eli Watson', email: 'eli.watson@ferris.edu', role: 'cs_helper', lastLogin: '2026-05-12T11:08:00', status: 'Active', initials: 'EW' },
  { id: 'u7', name: 'Priya Shah', email: 'priya.shah@ferris.edu', role: 'cs_helper', lastLogin: null, status: 'Inactive', initials: 'PS' },
];

const TEAMS = [
  { id: 't1', name: "Men's Hockey", sport: 'Hockey', rosterFiled: true, starterPack: { done: 22, total: 22 }, pendingForms: 0, budget: { allocated: 3200, spent: 2410 }, lastYearBudget: { allocated: 3000, spent: 2876 }, lastActivity: 'Today', status: 'compliant' },
  { id: 't2', name: "Women's Soccer", sport: 'Soccer', rosterFiled: true, starterPack: { done: 18, total: 22 }, pendingForms: 1, budget: { allocated: 1800, spent: 720 }, lastYearBudget: { allocated: 1700, spent: 1620 }, lastActivity: '2 days ago', status: 'attention' },
  { id: 't3', name: "Men's Lacrosse", sport: 'Lacrosse', rosterFiled: true, starterPack: { done: 15, total: 28 }, pendingForms: 3, budget: { allocated: 2200, spent: 1980 }, lastYearBudget: { allocated: 2000, spent: 1840 }, lastActivity: 'Yesterday', status: 'attention' },
  { id: 't4', name: 'Esports', sport: 'Esports', rosterFiled: true, starterPack: { done: 12, total: 14 }, pendingForms: 0, budget: { allocated: 900, spent: 340 }, lastYearBudget: { allocated: 600, spent: 580 }, lastActivity: 'Today', status: 'compliant' },
  { id: 't5', name: "Women's Volleyball", sport: 'Volleyball', rosterFiled: false, starterPack: { done: 0, total: 18 }, pendingForms: 0, budget: { allocated: 1500, spent: 0 }, lastYearBudget: { allocated: 1400, spent: 1390 }, lastActivity: '6 days ago', status: 'noncompliant' },
  { id: 't6', name: "Men's Soccer", sport: 'Soccer', rosterFiled: true, starterPack: { done: 24, total: 24 }, pendingForms: 0, budget: { allocated: 1800, spent: 1120 }, lastYearBudget: { allocated: 1700, spent: 1645 }, lastActivity: 'Today', status: 'compliant' },
  { id: 't7', name: 'Climbing', sport: 'Climbing', rosterFiled: true, starterPack: { done: 8, total: 12 }, pendingForms: 2, budget: { allocated: 600, spent: 410 }, lastYearBudget: { allocated: 500, spent: 472 }, lastActivity: '3 days ago', status: 'attention' },
  { id: 't8', name: "Men's Volleyball", sport: 'Volleyball', rosterFiled: true, starterPack: { done: 16, total: 16 }, pendingForms: 0, budget: { allocated: 1500, spent: 980 }, lastYearBudget: { allocated: 1400, spent: 1320 }, lastActivity: 'Yesterday', status: 'compliant' },
  { id: 't9', name: 'Wrestling', sport: 'Wrestling', rosterFiled: false, starterPack: { done: 4, total: 18 }, pendingForms: 1, budget: { allocated: 1400, spent: 0 }, lastYearBudget: { allocated: 1300, spent: 1255 }, lastActivity: '8 days ago', status: 'noncompliant' },
  { id: 't10', name: 'Bowling', sport: 'Bowling', rosterFiled: true, starterPack: { done: 10, total: 12 }, pendingForms: 0, budget: { allocated: 500, spent: 240 }, lastYearBudget: { allocated: 450, spent: 430 }, lastActivity: 'Today', status: 'attention' },
  { id: 't11', name: 'Cycling', sport: 'Cycling', rosterFiled: true, starterPack: { done: 14, total: 14 }, pendingForms: 0, budget: { allocated: 800, spent: 612 }, lastYearBudget: { allocated: 750, spent: 718 }, lastActivity: 'Yesterday', status: 'compliant' },
  { id: 't12', name: "Women's Hockey", sport: 'Hockey', rosterFiled: true, starterPack: { done: 19, total: 20 }, pendingForms: 1, budget: { allocated: 3200, spent: 2150 }, lastYearBudget: { allocated: 3000, spent: 3045 }, lastActivity: 'Today', status: 'attention' },
];

// First names + last names for roster mock
const FIRST = ['Alex','Jordan','Sam','Taylor','Morgan','Riley','Casey','Jamie','Avery','Quinn','Drew','Reese','Skyler','Parker','Hayden','Cameron','Sage','Logan','Emerson','Finley'];
const LAST = ['Nguyen','Patel','Garcia','Smith','Johnson','Williams','Brown','Davis','Wilson','Martinez','Anderson','Taylor','Thomas','Hernandez','Moore','Martin','Jackson','Thompson','White','Lopez'];

function genRoster(teamId, size, doneCount) {
  const out = [];
  for (let i = 0; i < size; i++) {
    const first = FIRST[(i * 7 + teamId.charCodeAt(1)) % FIRST.length];
    const last = LAST[(i * 3 + 11) % LAST.length];
    const allDone = i < doneCount;
    const wai = allDone || Math.random() > 0.4;
    const coc = allDone || Math.random() > 0.5;
    const con = allDone || Math.random() > 0.5;
    out.push({
      id: `${teamId}-m${i}`,
      name: `${first} ${last}`,
      email: `${first.toLowerCase()}.${last.toLowerCase()}${i}@ferris.edu`,
      waiver: allDone ? { signed: true, at: '2026-04-22T10:14:00' } : (wai ? { signed: true, at: '2026-04-26T09:30:00' } : { signed: false }),
      coc: allDone ? { signed: true, at: '2026-04-22T10:14:00' } : (coc ? { signed: true, at: '2026-04-27T11:02:00' } : { signed: false }),
      concussion: allDone ? { signed: true, at: '2026-04-22T10:14:00' } : (con ? { signed: true, at: '2026-04-28T16:48:00' } : { signed: false }),
    });
  }
  return out;
}

const ROSTERS = {};
TEAMS.forEach(t => { ROSTERS[t.id] = genRoster(t.id, t.starterPack.total || 12, t.starterPack.done); });

const EVENTS_PENDING = [
  { id: 'e1', teamId: 't1', team: "Men's Hockey", type: 'Away', name: 'vs Davenport', date: '2026-06-04', daysAway: 21, location: 'Grand Rapids, MI', submittedAt: '2026-05-12', transportation: 'Van + 1 car' },
  { id: 'e2', teamId: 't3', team: "Men's Lacrosse", type: 'Home', name: 'vs Saginaw Valley', date: '2026-05-25', daysAway: 11, location: 'IM Field 1', submittedAt: '2026-05-14' },
  { id: 'e3', teamId: 't6', team: "Men's Soccer", type: 'Away', name: 'vs Northwood', date: '2026-05-28', daysAway: 14, location: 'Midland, MI', submittedAt: '2026-05-13', transportation: 'Charter bus' },
  { id: 'e4', teamId: 't4', team: 'Esports', type: 'Home', name: 'Spring open finals', date: '2026-06-12', daysAway: 29, location: 'Esports lounge, UC', submittedAt: '2026-05-13' },
];

const EVENTS_APPROVED = [
  { id: 'a1', teamId: 't2', team: "Women's Soccer", type: 'Home', name: 'vs Aquinas', date: '2026-05-18', daysAway: 4, location: 'IM Field 2', submittedAt: '2026-04-30', approvedBy: 'Justin Reilly', approvedAt: '2026-05-01 09:14' },
  { id: 'a2', teamId: 't1', team: "Men's Hockey", type: 'Away', name: 'vs Bowling Green', date: '2026-05-21', daysAway: 7, location: 'Bowling Green, OH', submittedAt: '2026-04-22', approvedBy: 'Zac Holland', approvedAt: '2026-04-23 14:01', transportation: 'Charter bus' },
  { id: 'a3', teamId: 't8', team: "Men's Volleyball", type: 'Home', name: 'vs Hope College', date: '2026-05-20', daysAway: 6, location: 'Court 2', submittedAt: '2026-04-28', approvedBy: 'Justin Reilly', approvedAt: '2026-04-29 11:23' },
  { id: 'a4', teamId: 't11', team: 'Cycling', type: 'Away', name: 'Lakeshore criterium', date: '2026-05-23', daysAway: 9, location: 'Muskegon, MI', submittedAt: '2026-05-02', approvedBy: 'Maya Brooks', approvedAt: '2026-05-03 08:40', transportation: 'Personal vehicles' },
];

const FACILITIES = ['IM Field 1', 'IM Field 2', 'Court 1', 'Court 2', 'Court 3', 'Court 4'];
const FACILITY_HOURS = []; for (let h = 6; h <= 21; h++) FACILITY_HOURS.push(h);

// Reservations: { facility, day (0-6 Mon..Sun), startHr, endHr, team, kind, status }
const RESERVATIONS = [
  { id: 'r1', facility: 'IM Field 1', day: 0, startHr: 17, endHr: 19, team: "Men's Soccer", kind: 'practice', status: 'approved' },
  { id: 'r2', facility: 'IM Field 1', day: 1, startHr: 18, endHr: 20, team: "Women's Soccer", kind: 'practice', status: 'approved' },
  { id: 'r3', facility: 'IM Field 1', day: 5, startHr: 14, endHr: 17, team: "Men's Lacrosse", kind: 'game', status: 'approved' },
  { id: 'r4', facility: 'IM Field 2', day: 2, startHr: 16, endHr: 18, team: 'Wrestling', kind: 'practice', status: 'pending' },
  { id: 'r5', facility: 'IM Field 2', day: 4, startHr: 17, endHr: 19, team: "Women's Soccer", kind: 'practice', status: 'approved' },
  { id: 'r6', facility: 'Court 1', day: 0, startHr: 19, endHr: 21, team: "Men's Volleyball", kind: 'practice', status: 'approved' },
  { id: 'r7', facility: 'Court 1', day: 2, startHr: 18, endHr: 21, team: "Men's Volleyball", kind: 'game', status: 'approved' },
  { id: 'r8', facility: 'Court 2', day: 1, startHr: 19, endHr: 21, team: "Women's Volleyball", kind: 'practice', status: 'pending' },
  { id: 'r9', facility: 'Court 2', day: 3, startHr: 18, endHr: 20, team: "Women's Volleyball", kind: 'practice', status: 'approved' },
  { id: 'r10', facility: 'Court 3', day: 2, startHr: 20, endHr: 22, team: 'Climbing', kind: 'practice', status: 'approved' },
  { id: 'r11', facility: 'Court 4', day: 4, startHr: 18, endHr: 21, team: 'Bowling', kind: 'practice', status: 'pending' },
  { id: 'r12', facility: 'Court 3', day: 5, startHr: 12, endHr: 15, team: 'Esports', kind: 'game', status: 'approved' },
];

// Calendar events for May 2026 (display month)
const CAL_EVENTS = [
  { date: '2026-05-04', team: "Women's Soccer", type: 'home', label: 'vs Hope' },
  { date: '2026-05-07', team: "Men's Lacrosse", type: 'away', label: 'vs SVSU' },
  { date: '2026-05-11', team: "Men's Hockey", type: 'away', label: 'vs Davenport' },
  { date: '2026-05-14', team: "Men's Volleyball", type: 'home', label: 'vs GVSU' },
  { date: '2026-05-15', team: 'Cycling', type: 'away', label: 'Crit race' },
  { date: '2026-05-18', team: "Women's Soccer", type: 'home', label: 'vs Aquinas' },
  { date: '2026-05-20', team: "Men's Volleyball", type: 'home', label: 'vs Hope' },
  { date: '2026-05-21', team: "Men's Hockey", type: 'away', label: 'vs BGSU' },
  { date: '2026-05-23', team: 'Cycling', type: 'away', label: 'Lakeshore' },
  { date: '2026-05-25', team: "Men's Lacrosse", type: 'home', label: 'vs SVSU', pending: true },
  { date: '2026-05-28', team: "Men's Soccer", type: 'away', label: 'vs Northwood', pending: true },
];

// Transactions per team
const SAF_CATEGORIES = [
  'Travel · lodging',
  'Gas reimbursement',
  'League / conference fees',
  'Tournament / entry fees',
  'Officials / referees',
  'Equipment / uniforms',
  'Facility rental',
  'Meals / per diem',
  'Other',
];
const TX_CATS = SAF_CATEGORIES;
const E_BOARD_POSITIONS = ['President','Vice president','Treasurer','Secretary','Captain','Equipment manager','Safety officer'];
const SAF_TEMPLATES = {
  'Travel · lodging': [
    { desc: 'Hotel block', vendor: 'Hilton Grand Rapids', justify: 'Two-night lodging for 14 players, vs Davenport away series.' },
    { desc: 'Conference housing block', vendor: 'Holiday Inn Express', justify: 'Regional tournament housing, 12 athletes · 2 nights.' },
  ],
  'Gas reimbursement': [
    { desc: 'Gas · Muskegon trip', vendor: 'Speedway', justify: 'Three cars, round trip to Lakeshore criterium.', gas: { cars: 3, from: '901 S State St, Big Rapids MI', to: '1100 W Western Ave, Muskegon MI' } },
    { desc: 'Gas · vs Aquinas', vendor: 'BP', justify: 'Two cars, round trip to Grand Rapids.', gas: { cars: 2, from: '901 S State St, Big Rapids MI', to: '1700 Fulton St E, Grand Rapids MI' } },
  ],
  'League / conference fees': [
    { desc: 'ACHA league dues', vendor: 'American Collegiate Hockey Association', justify: 'Annual league registration, Division II.' },
    { desc: 'NIRSA membership renewal', vendor: 'NIRSA', justify: 'Conference dues, 2026 season.' },
  ],
  'Tournament / entry fees': [
    { desc: 'Spring open entry', vendor: 'Midwest Lacrosse Conference', justify: 'Tournament registration, 4-team bracket.' },
    { desc: 'Regional qualifier entry', vendor: 'Cycling US Collegiate', justify: 'Team entry for two-day stage race.' },
  ],
  'Officials / referees': [
    { desc: 'Referee crew, vs Hope', vendor: 'GLIAC Officials Pool', justify: 'Two referees + scorekeeper for home game.' },
    { desc: 'Linesmen stipend', vendor: 'Big Rapids Officials Assoc.', justify: 'Two linesmen, three-game home stand.' },
  ],
  'Equipment / uniforms': [
    { desc: 'Jerseys reorder', vendor: 'BSN Sports', justify: 'Replacement away jerseys, six players, sizing changes.' },
    { desc: 'Practice balls', vendor: 'Dick’s Team Sports', justify: 'Replacement match balls and practice balls for spring season.' },
  ],
  'Facility rental': [
    { desc: 'Rink rental', vendor: 'Ewigleben Ice Arena', justify: 'Two-hour weekly rental block, spring season.' },
    { desc: 'Court resurfacing share', vendor: 'FSU Facilities Services', justify: 'Shared cost of resurfacing Court 2, club portion.' },
  ],
  'Meals / per diem': [
    { desc: 'Per diem · away weekend', vendor: 'Per diem disbursement', justify: 'Player per diem, two-day away series at Bowling Green.' },
    { desc: 'Team meal, postgame', vendor: 'Schuberg’s', justify: 'Postgame meal for visiting team, hosting agreement.' },
  ],
  'Other': [
    { desc: 'Banquet deposit', vendor: 'Holiday Inn Big Rapids', justify: 'Deposit for end-of-season awards banquet.' },
    { desc: 'CPR recertification', vendor: 'American Red Cross', justify: 'Safety officer recertification, biennial requirement.' },
  ],
};

const OFFICERS_BY_TEAM = {
  't1': { name: 'Riley Garcia', position: 'President', email: 'riley.garcia@ferris.edu' },
  't2': { name: 'Sage Wilson', position: 'President', email: 'sage.wilson@ferris.edu' },
  't3': { name: 'Logan Thompson', position: 'Captain', email: 'logan.thompson@ferris.edu' },
  't4': { name: 'Quinn Davis', position: 'President', email: 'quinn.davis@ferris.edu' },
  't5': { name: 'Avery Martin', position: 'President', email: 'avery.martin@ferris.edu' },
  't6': { name: 'Jordan Patel', position: 'Captain', email: 'jordan.patel@ferris.edu' },
  't7': { name: 'Skyler Lopez', position: 'President', email: 'skyler.lopez@ferris.edu' },
  't8': { name: 'Drew Anderson', position: 'Captain', email: 'drew.anderson@ferris.edu' },
  't9': { name: 'Hayden Moore', position: 'Captain', email: 'hayden.moore@ferris.edu' },
  't10': { name: 'Reese Taylor', position: 'Treasurer', email: 'reese.taylor@ferris.edu' },
  't11': { name: 'Emerson Jackson', position: 'President', email: 'emerson.jackson@ferris.edu' },
  't12': { name: 'Cameron White', position: 'Captain', email: 'cameron.white@ferris.edu' },
};

// Multi-officer e-board per team (4-6 members each)
const POSITIONS_FULL = ['President','Vice president','Treasurer','Secretary','Safety officer','Equipment manager'];

function genEboard(teamId, primaryOfficer) {
  // Build deterministic set of officers from FIRST/LAST seeds with primary up top
  const seed = teamId.charCodeAt(1) + (teamId.length > 2 ? teamId.charCodeAt(2) : 0);
  const board = [];
  POSITIONS_FULL.forEach((pos, i) => {
    if (pos === primaryOfficer.position) {
      board.push({ id: `${teamId}-eb${i}`, name: primaryOfficer.name, position: pos, email: primaryOfficer.email, phone: '(231) 555-0' + (200 + seed + i), termsServed: 1 + (i % 3), trainingDone: true, primary: true });
    } else {
      const fn = FIRST[(seed + i * 5) % FIRST.length];
      const ln = LAST[(seed * 3 + i * 7) % LAST.length];
      board.push({
        id: `${teamId}-eb${i}`,
        name: `${fn} ${ln}`,
        position: pos,
        email: `${fn.toLowerCase()}.${ln.toLowerCase()}@ferris.edu`,
        phone: '(231) 555-0' + (200 + seed + i * 3),
        termsServed: ((seed + i) % 3) + 1,
        trainingDone: (seed + i) % 5 !== 0,
        primary: false,
      });
    }
  });
  return board.slice(0, 4 + (seed % 3)); // 4-6 members
}

const EBOARDS = {};
TEAMS.forEach(t => {
  const primary = OFFICERS_BY_TEAM[t.id] || { name: 'Team officer', position: 'President', email: 'officer@ferris.edu' };
  EBOARDS[t.id] = genEboard(t.id, primary);
});

const COACHES = {
  't1': { name: 'Coach R. Allen', email: 'r.allen@ferris.edu', kind: 'Head coach', volunteer: false },
  't2': { name: 'Coach L. Pham', email: 'l.pham@ferris.edu', kind: 'Head coach', volunteer: true },
  't3': { name: 'Coach M. Diaz', email: 'm.diaz@ferris.edu', kind: 'Head coach', volunteer: true },
  't4': null,
  't5': { name: 'Coach T. Becker', email: 't.becker@ferris.edu', kind: 'Advisor', volunteer: true },
  't6': { name: 'Coach K. Park', email: 'k.park@ferris.edu', kind: 'Head coach', volunteer: false },
  't7': { name: 'Coach J. Reyes', email: 'j.reyes@ferris.edu', kind: 'Instructor', volunteer: true },
  't8': { name: 'Coach C. Hayes', email: 'c.hayes@ferris.edu', kind: 'Head coach', volunteer: true },
  't9': { name: 'Coach D. Larson', email: 'd.larson@ferris.edu', kind: 'Head coach', volunteer: true },
  't10': null,
  't11': null,
  't12': { name: 'Coach S. Wagner', email: 's.wagner@ferris.edu', kind: 'Head coach', volunteer: true },
};

function genTx(team, count, total) {
  const out = [];
  for (let i = 0; i < count; i++) {
    const amt = Math.round((total / count) * (0.6 + Math.random() * 0.8));
    const cat = TX_CATS[(i * 3 + team.id.charCodeAt(1)) % TX_CATS.length];
    const monthDay = (5 + i * 2) % 28 + 1;
    const templates = SAF_TEMPLATES[cat] || SAF_TEMPLATES['Other'];
    const tpl = templates[i % templates.length];
    const officer = OFFICERS_BY_TEAM[team.id] || { name: 'Team officer', position: 'President', email: 'officer@ferris.edu' };
    const reimburse = ['Gas reimbursement','Meals / per diem'].includes(cat) || (i % 4 === 0);
    const statusPool = ['posted','posted','posted','val-confirmed','stoney-signed','submitted','returned'];
    const status = statusPool[(i * 5 + team.id.charCodeAt(1)) % statusPool.length];
    const submittedAt = `2026-${String(4 + Math.floor(i/4)).padStart(2,'0')}-${String(monthDay).padStart(2,'0')}T${String(9 + (i%6)).padStart(2,'0')}:${String((i*7)%60).padStart(2,'0')}:00`;
    function addDays(iso, d) {
      const x = new Date(iso); x.setDate(x.getDate() + d);
      return x.toISOString().slice(0, 19);
    }
    const stoneyAt = (status === 'submitted' || status === 'returned') ? null : addDays(submittedAt, 1);
    const valAt = (status === 'submitted' || status === 'returned' || status === 'stoney-signed') ? null : addDays(submittedAt, 2);
    const postedAt = (status === 'posted') ? addDays(submittedAt, 3) : null;
    // Reimbursement check status — only for reimbursement SAFs that are posted
    let checkStatus = null, checkAt = null, checkNumber = null;
    if (reimburse && status === 'posted') {
      const pool = ['requested', 'mailed', 'mailed', 'cashed', 'cashed'];
      checkStatus = pool[(i * 3 + team.id.charCodeAt(1)) % pool.length];
      checkAt = addDays(postedAt, checkStatus === 'requested' ? 0 : checkStatus === 'mailed' ? 2 : 7);
      checkNumber = '20' + String(2600 + (team.id.charCodeAt(1) * 13 + i * 7) % 400);
    }
    const returnReason = status === 'returned'
      ? ['Missing receipt — please attach itemized receipt.','Vendor address incomplete.','Need updated justification tied to a specific event.','Reimbursement amount over $200 — needs E-board approval.'][i % 4]
      : null;
    out.push({
      id: `${team.id}-tx${i}`,
      teamId: team.id,
      date: `2026-${String(4 + Math.floor(i/4)).padStart(2,'0')}-${String(monthDay).padStart(2,'0')}`,
      desc: tpl.desc,
      vendor: { name: tpl.vendor, phone: '(231) 555-0' + (100 + i), email: tpl.vendor.toLowerCase().replace(/[^a-z]+/g, '') + '@vendor.com', address: '1234 Main St, Grand Rapids MI' },
      amount: amt,
      category: cat,
      isReimbursement: reimburse,
      justification: tpl.justify,
      receipt: status === 'submitted' && i % 3 === 0 ? null : { filename: `receipt-${team.id}-${i}.pdf`, size: '142 KB', kind: 'PDF' },
      gas: tpl.gas || null,
      officer,
      status,
      workflow: {
        submitted: { at: submittedAt, by: officer.name },
        stoneySigned: stoneyAt ? { at: stoneyAt, by: 'Stoney Carter' } : null,
        valConfirmed: valAt ? { at: valAt, by: 'Val Marquez' } : null,
        posted: postedAt ? { at: postedAt, by: 'Val Marquez' } : null,
        returned: returnReason ? { at: addDays(submittedAt, 1), by: 'Stoney Carter', reason: returnReason } : null,
      },
      check: checkStatus ? { status: checkStatus, at: checkAt, number: checkNumber } : null,
      enteredBy: i % 3 === 0 ? 'Val Marquez' : (i % 3 === 1 ? 'Stoney Carter' : 'Maya Brooks'),
      submittedAt,
    });
  }
  return out;
}
const TRANSACTIONS = {};
TEAMS.forEach(t => {
  const count = t.budget.spent > 0 ? Math.max(3, Math.min(8, Math.round(t.budget.spent / 200))) : 0;
  TRANSACTIONS[t.id] = genTx(t, count, t.budget.spent);
});

// Featured demo: a freshly-submitted "purchased rental" SAF
// Surfaces at the top of every list and threads the full workflow demo.
const RENTAL_DEMO = {
  id: 't1-rental-demo',
  teamId: 't1',
  date: '2026-05-15',
  desc: 'Ice rink rental \u00b7 4-week practice block',
  vendor: {
    name: 'Ewigleben Ice Arena',
    phone: '(231) 591-2851',
    address: '401 S State St, Big Rapids MI 49307',
    email: 'rentals@ewigleben.ferris.edu',
  },
  amount: 1240,
  category: 'Facility rental',
  isReimbursement: false,
  justification: 'Purchased rental: four-week weekly practice block (May 19 - June 16, Tues 6-8pm) at the Ewigleben Arena. Required to maintain ACHA practice minimums before the June 4 Davenport away series. Quote attached; rate locked at the educational use price of $310/night for 4 nights.',
  receipt: { filename: 'ewigleben-quote-may15.pdf', size: '186 KB', kind: 'PDF' },
  gas: null,
  officer: { name: 'Riley Garcia', position: 'President', email: 'riley.garcia@ferris.edu' },
  status: 'submitted',
  workflow: {
    submitted: { at: '2026-05-15T08:42:00', by: 'Riley Garcia' },
    stoneySigned: null,
    valConfirmed: null,
    posted: null,
    returned: null,
  },
  enteredBy: 'Riley Garcia (via Canvas)',
  submittedAt: '2026-05-15T08:42:00',
  isDemoRental: true,
};

// Push to the front so it appears as the newest SAF
TRANSACTIONS['t1'] = [RENTAL_DEMO, ...(TRANSACTIONS['t1'] || [])];

window.AppData = {
  ROLES, USERS, TEAMS, ROSTERS,
  EVENTS_PENDING, EVENTS_APPROVED,
  FACILITIES, FACILITY_HOURS, RESERVATIONS,
  CAL_EVENTS, TRANSACTIONS, TX_CATS,
  SAF_CATEGORIES, E_BOARD_POSITIONS, OFFICERS_BY_TEAM,
  EBOARDS, COACHES, POSITIONS_FULL,
};

// ---- Time / date formatters: forced 12-hour ET ----
window.Fmt = {
  time(input) {
    if (!input) return '';
    const d = typeof input === 'string' ? new Date(input) : input;
    return d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true, timeZone: 'America/New_York' }) + ' ET';
  },
  // Convert an HH:mm 24-hr string ("18:00") to "6:00 PM"
  time24To12(str) {
    if (!str) return '';
    const [h, m] = str.split(':').map(Number);
    if (Number.isNaN(h)) return str;
    const period = h >= 12 ? 'PM' : 'AM';
    const hr = h % 12 === 0 ? 12 : h % 12;
    return `${hr}:${String(m || 0).padStart(2, '0')} ${period}`;
  },
  hour12(hour24) {
    const h = hour24 % 12 === 0 ? 12 : hour24 % 12;
    return `${h}${hour24 >= 12 ? 'p' : 'a'}`;
  },
  date(input, opts = {}) {
    if (!input) return '';
    const d = typeof input === 'string' ? new Date(input + (input.length === 10 ? 'T12:00:00' : '')) : input;
    return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: opts.year ? 'numeric' : undefined, weekday: opts.weekday });
  },
  dateTime(input) {
    if (!input) return '';
    const d = typeof input === 'string' ? new Date(input) : input;
    return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) + ' \u00b7 ' +
      d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true }) + ' ET';
  },
  fullDateTime(input) {
    if (!input) return '';
    const d = typeof input === 'string' ? new Date(input) : input;
    return d.toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' }) + ' \u00b7 ' +
      d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true }) + ' ET';
  },
};
