// admin-state-4.jsx — AdminProvider context + tax engine helpers.

// ── Multi-state tax allocation engine ────────────────────────
// Given an employee + array of timecard blocks { hrs, state }, allocate
// gross wages across states per the company's elected tax policy:
//   • 'home'       — All wages to resident state (simplest; not always legal)
//   • 'work'       — Each state's wages taxed by that state (most defensible
//                    for short stints; uses day count to avoid de minimis nexus)
//   • 'hybrid'     — Apply reciprocal-state rules + credit on the resident
//                    state return for tax paid to nonresident states
function allocateWages(employee, blocks, policy = 'hybrid') {
  const rate = employee.baseRate || 0;
  const out = {};
  for (const b of blocks) {
    const wage = b.hrs * rate;
    out[b.state] = (out[b.state] || 0) + wage;
  }

  const breakdown = Object.entries(out).map(([state, wage]) => {
    const sm = STATES.find(s => s.code === state) || { tax: 0, reciprocal: [] };
    const home = STATES.find(s => s.code === employee.resident) || { tax: 0, reciprocal: [] };
    const isHome = state === employee.resident;
    const isReciprocal = sm.reciprocal.includes(employee.resident);

    let taxedBy, taxRate, taxAmt, credit, note;
    if (policy === 'home') {
      taxedBy = employee.resident;
      taxRate = home.tax;
      taxAmt = wage * home.tax;
      note = 'All wages taxed to resident state (home policy).';
    } else if (policy === 'work') {
      taxedBy = state;
      taxRate = sm.tax;
      taxAmt = wage * sm.tax;
      note = isHome ? 'Resident state.' : 'Wages taxed where earned.';
    } else {
      // hybrid
      if (isHome) {
        taxedBy = employee.resident;
        taxRate = home.tax;
        taxAmt = wage * home.tax;
        note = 'Resident state — withheld locally.';
      } else if (isReciprocal) {
        taxedBy = employee.resident;
        taxRate = home.tax;
        taxAmt = wage * home.tax;
        note = `${state} ↔ ${employee.resident} are reciprocal — taxed to resident.`;
      } else {
        taxedBy = state;
        taxRate = sm.tax;
        taxAmt = wage * sm.tax;
        // Resident-state credit equals the lesser of nonresident-state tax
        // paid and the resident-state tax that would have applied to those wages.
        const wouldHavePaid = wage * home.tax;
        credit = Math.min(taxAmt, wouldHavePaid);
        note = `Nonresident state. Credit available on ${employee.resident} return.`;
      }
    }
    return { state, wage, taxedBy, taxRate, taxAmt, credit: credit || 0, note };
  });
  return breakdown;
}

// ── Railroad Retirement compute ──────────────────────────────
function computeRRTA(employee, grossYTD, grossThisRun, opts = {}) {
  const wantTier1     = opts.tier1     !== false;
  const wantTier2     = opts.tier2     !== false;
  const wantMedicare  = opts.medicare  !== false;
  if (!employee.rrbContributor) {
    // Not in railroad retirement — falls under FICA instead (SS + Medicare).
    return {
      enrolled: false,
      lines: [
        { label: 'Social Security (employee)', rate: 0.062,  base: Math.min(grossThisRun, 168600), amount: Math.min(grossThisRun, 168600) * 0.062 },
        { label: 'Medicare (employee)',        rate: 0.0145, base: grossThisRun,                   amount: grossThisRun * 0.0145 },
      ],
      employer: [
        { label: 'Social Security (employer)', rate: 0.062,  base: Math.min(grossThisRun, 168600), amount: Math.min(grossThisRun, 168600) * 0.062 },
        { label: 'Medicare (employer)',        rate: 0.0145, base: grossThisRun,                   amount: grossThisRun * 0.0145 },
      ],
    };
  }

  const employee_lines = [];
  const employer_lines = [];

  if (wantTier1) {
    const t = RRTA_2026.tier1;
    const remaining = Math.max(0, t.wageBase - grossYTD);
    const base = Math.min(grossThisRun, remaining);
    employee_lines.push({ label: 'RRTA Tier I (employee · 6.20%)',  rate: t.employee, base, amount: base * t.employee });
    employer_lines.push({ label: 'RRTA Tier I (employer · 6.20%)',  rate: t.employer, base, amount: base * t.employer });
  }
  if (wantTier2) {
    const t = RRTA_2026.tier2;
    const remaining = Math.max(0, t.wageBase - grossYTD);
    const base = Math.min(grossThisRun, remaining);
    employee_lines.push({ label: 'RRTA Tier II (employee · 4.90%)', rate: t.employee, base, amount: base * t.employee });
    employer_lines.push({ label: 'RRTA Tier II (employer · 13.10%)',rate: t.employer, base, amount: base * t.employer });
  }
  if (wantMedicare) {
    const m = RRTA_2026.medicare;
    employee_lines.push({ label: 'Medicare (employee · 1.45%)', rate: m.rate, base: grossThisRun, amount: grossThisRun * m.rate });
    employer_lines.push({ label: 'Medicare (employer · 1.45%)', rate: m.rate, base: grossThisRun, amount: grossThisRun * m.rate });
    if (grossYTD + grossThisRun > m.additional.threshold) {
      const over = Math.max(0, grossYTD + grossThisRun - m.additional.threshold) - Math.max(0, grossYTD - m.additional.threshold);
      if (over > 0) {
        employee_lines.push({ label: 'Add\u2019l Medicare (employee · 0.90%)', rate: m.additional.rate, base: over, amount: over * m.additional.rate });
      }
    }
  }
  return { enrolled: true, lines: employee_lines, employer: employer_lines };
}

// ── Mock YTD for current employees (for the RRB view) ────────
const YTD_GROSS = {
  'e-2241': 41250,
  'e-1907': 47800,
  'e-3025': 32100,
  'e-4488': 49600,
  'e-5512': 28400,
  'e-6601': 56200,
  'e-7733': 36900,
  'e-8814': 33700,
};

// ── Provider ────────────────────────────────────────────────
const AdminCtx = createContext(null);

// Normalize a Supabase timecard to the admin UI shape
function normalizeSupabaseTimecard(row) {
  const emp = row.employees || {};
  const job = row.jobs || {};
  const empId = row.employee_id || '';
  const jobId = row.job_id || '';
  // Map status from Supabase schema to UI schema
  const statusMap = { draft: 'pending-ops', submitted: 'pending-ops', supervisor_approved: 'pending-acct', payroll_approved: 'approved', rejected: 'rejected' };
  const status = statusMap[row.status] || row.status || 'pending-ops';
  // Build blocks from state_allocation or infer from hours
  const alloc = row.state_allocation || [];
  const blocks = alloc.length ? alloc.map(a => ({
    code: row.rfl_activity_code || 'F10',
    hrs: a.hours || 0,
    state: a.state || 'TX',
  })) : [{ code: row.rfl_activity_code || 'F10', hrs: (row.regular_hours || 0) + (row.overtime_hours || 0), state: 'TX' }];
  const total = blocks.reduce((s, b) => s + b.hrs, 0);
  return {
    id: row.id,
    employeeId: empId,
    jobId: jobId,
    date: row.work_date || '',
    blocks,
    total,
    regular: row.regular_hours || Math.min(8, total),
    overtime: row.overtime_hours || Math.max(0, total - 8),
    status,
    submitted: !!row.submitted_at,
    gpsVerified: false,
    flags: [],
    _dbRow: row,
  };
}

// Normalize a Supabase employee to the admin UI shape
function normalizeSupabaseEmployee(row) {
  return {
    id: row.id,
    name: [row.first_name, row.last_name].filter(Boolean).join(" "),
    badge: row.employee_number || '',
    role: row.rfl_codes && row.rfl_codes.length ? row.rfl_codes[0] : 'RWIC',
    baseRate: row.base_rate || 0,
    resident: row.resident_state || row.state || 'MT',
    payrollFreq: 'bi-weekly',
    rrbContributor: row.rrb_contributor || false,
    hireDate: row.hire_date || '',
    cert: (row.certifications || []).map(c => c.type).join(' · '),
    certExpires: (row.certifications || []).map(c => c.expires).filter(Boolean).sort().reverse()[0] || '',
    status: row.termination_date ? 'off-duty' : 'on-duty',
    homeBase: '',
    phone: row.phone || '',
    avatar: [row.first_name, row.last_name].filter(Boolean).map(n => n[0]).join('').toUpperCase(),
    _dbId: row.id,
  };
}

// Normalize a Supabase job to the admin UI shape
function normalizeSupabaseJob(row) {
  const cc = row.client_companies || {};
  return {
    id: row.job_number || row.id,
    clientId: cc.railroad_code ? 'cli-' + cc.railroad_code.toLowerCase() : '',
    projectNumber: row.job_number || '',
    name: row.name || row.location || '',
    railroad: row.railroad || '',
    subdivision: row.subdivision || '',
    mp: '',
    state: row.state || '',
    start: row.start_date || '',
    end: row.end_date || '',
    status: row.status || 'active',
    billRate: 0,
    foreman: '',
    contractor: '',
    rwicIds: [],
    _dbId: row.id,
  };
}

function AdminProvider({ children }) {
  // Stamp the demo "current" pay period
  const [periodStart, setPeriodStart] = useState('2026-05-18');
  const [periodEnd,   setPeriodEnd]   = useState('2026-05-31');

  // Tax policy (per-company setting; default hybrid)
  const [taxPolicy, setTaxPolicy] = useState('hybrid'); // 'home' | 'work' | 'hybrid'
  // RRB enabled at the company level — OFF by default.
  const [rrbEnabled, setRrbEnabled] = useState(() => {
    try { const c = (dbLoad().company || {}); return c.rrbEnabled === true; } catch (e) { return false; }
  });
  const [icExempt, setICExempt] = useState(false);

  // Live data from Supabase (null = not loaded yet)
  const [liveEmployees, setLiveEmployees] = useState(null);
  const [liveJobs, setLiveJobs] = useState(null);
  const [liveTimecards, setLiveTimecards] = useState(null);

  // Load live data from Supabase when session is available
  useEffect(() => {
    const sess = (typeof RFP !== 'undefined' && RFP.session) ? RFP.session() : null;
    if (!sess || !window._rfpSupabase) return;
    let cancelled = false;

    async function loadAll() {
      const sb = window._rfpSupabase;
      try {
        // Load employees
        const { data: empData } = await sb.from("employees").select("*");
        if (empData && !cancelled) setLiveEmployees(empData.map(normalizeSupabaseEmployee));
      } catch (e) { console.warn("Admin: employees load:", e.message); }
      try {
        // Load jobs with client company info
        const { data: jobData } = await sb.from("jobs").select("*, client_companies(name, railroad_code)");
        if (jobData && !cancelled) setLiveJobs(jobData.map(normalizeSupabaseJob));
      } catch (e) { console.warn("Admin: jobs load:", e.message); }
      try {
        // Load timecards with employee and job info
        const { data: tcData } = await sb.from("timecards").select("*, employees(first_name, last_name, employee_number), jobs(job_number, name)");
        if (tcData && !cancelled) setLiveTimecards(tcData.map(normalizeSupabaseTimecard));
      } catch (e) { console.warn("Admin: timecards load:", e.message); }
    }

    loadAll();
    return () => { cancelled = true; };
  }, []);

  // Live timecards — merge mock data + localStorage tablet submissions + live Supabase
  const [timecards, setTimecards] = useState(() => {
    const tablet = (typeof readTabletTimecards === 'function') ? readTabletTimecards() : [];
    const existingIds = new Set(TIMECARDS.map(t => t.id));
    const fresh = tablet.filter(t => !existingIds.has(t.id));
    return [...fresh, ...TIMECARDS];
  });

  // When Supabase timecards load, merge them in (prepend live records, keep mock for demo display)
  useEffect(() => {
    if (!liveTimecards) return;
    setTimecards(curr => {
      const liveIds = new Set(liveTimecards.map(t => t.id));
      // Keep mock/tablet records that aren't in the live set (they're the rich demo data)
      const kept = curr.filter(t => !liveIds.has(t.id));
      return [...liveTimecards, ...kept];
    });
  }, [liveTimecards]);

  // Re-poll localStorage when the window regains focus (tablet submitted in another tab)
  useEffect(() => {
    const sync = () => {
      if (typeof readTabletTimecards !== 'function') return;
      const tablet = readTabletTimecards();
      if (tablet.length) {
        setTimecards(curr => {
          const ids = new Set(curr.map(t => t.id));
          const fresh = tablet.filter(t => !ids.has(t.id));
          return fresh.length ? [...fresh, ...curr] : curr;
        });
      }
      if (typeof readTabletSubmissions === 'function') {
        const subs = readTabletSubmissions();
        if (subs.length) {
          setSubmissions(curr => {
            const ids = new Set(curr.map(s => s.id));
            const fresh = subs.filter(s => !ids.has(s.id));
            return fresh.length ? [...fresh, ...curr] : curr;
          });
        }
      }
    };
    window.addEventListener('focus', sync);
    const iv = setInterval(sync, 4000);
    return () => { window.removeEventListener('focus', sync); clearInterval(iv); };
  }, []);

  // Field submissions (briefings + reports) → Safety/Compliance queue
  const [submissions, setSubmissions] = useState(() =>
    (typeof readTabletSubmissions === 'function') ? readTabletSubmissions() : []
  );
  const reviewSubmission = useCallback((id, status) => {
    setSubmissions(subs => subs.map(s => s.id === id ? { ...s, status } : s));
  }, []);

  const updateTimecard = useCallback((id, patch) => {
    setTimecards(tcs => tcs.map(t => t.id === id ? { ...t, ...patch } : t));
    // Also persist approval status to Supabase when available
    if (patch.status && window._rfpSupabase) {
      const statusMap = { 'pending-ops': 'submitted', 'pending-acct': 'supervisor_approved', approved: 'payroll_approved', rejected: 'rejected' };
      const sbStatus = statusMap[patch.status] || patch.status;
      // Only update if it's a real UUID (Supabase IDs), not mock IDs
      if (id && !id.startsWith('tc-e-') && !id.startsWith('tc-tablet-')) {
        window._rfpSupabase.from("timecards").update({ status: sbStatus }).eq("id", id).then(({ error }) => {
          if (error) console.warn("Timecard status update:", error.message);
        });
      }
    }
  }, []);

  // Drawer / modal state
  const [employeeDrawer, setEmployeeDrawer] = useState(null);
  const [timecardDrawer, setTimecardDrawer] = useState(null);
  const [payrollWizard, setPayrollWizard] = useState(false);
  const [activeDoc, setActiveDoc] = useState(null); // { kind, payload, title, subtitle, file }
  const launchDoc = useCallback((doc) => setActiveDoc(doc), []);

  // Toasts
  const [toasts, setToasts] = useState([]);
  const toast = useCallback((text, kind = 'info', ms = 2800) => {
    const id = A_uid('t');
    setToasts(t => [...t, { id, text, kind }]);
    setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), ms);
  }, []);

  const value = useMemo(() => ({
    periodStart, periodEnd, setPeriodStart, setPeriodEnd,
    taxPolicy, setTaxPolicy,
    rrbEnabled, setRrbEnabled,
    icExempt, setICExempt,
    timecards, updateTimecard,
    submissions, reviewSubmission,
    // Use live Supabase data when available, fall back to static mock data
    employees: liveEmployees && liveEmployees.length > 0 ? liveEmployees : EMPLOYEES,
    jobs: liveJobs && liveJobs.length > 0 ? liveJobs : JOBS,
    clients: CLIENTS,
    integrations: INTEGRATIONS,
    managers: (typeof MANAGERS !== 'undefined') ? MANAGERS : [],
    payrollRuns: PAYROLL_RUNS, exceptions: EXCEPTIONS, audit: AUDIT, ytdGross: YTD_GROSS,
    employeeDrawer, setEmployeeDrawer,
    timecardDrawer, setTimecardDrawer,
    payrollWizard, setPayrollWizard,
    activeDoc, setActiveDoc, launchDoc,
    toasts, toast,
    isLive: !!(liveEmployees || liveJobs || liveTimecards),
  }), [periodStart, periodEnd, taxPolicy, rrbEnabled, icExempt, timecards, updateTimecard, submissions, reviewSubmission, liveEmployees, liveJobs, liveTimecards, employeeDrawer, timecardDrawer, payrollWizard, activeDoc, launchDoc, toasts, toast]);

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

const useAdmin = () => useContext(AdminCtx);

Object.assign(window, {
  AdminCtx, AdminProvider, useAdmin,
  allocateWages, computeRRTA, YTD_GROSS,
});
