import { useState, useEffect, useCallback } from 'react'
import { ChevronLeft, ChevronRight, ChevronDown, Download } from 'lucide-react'
import {
  BarChart, Bar, XAxis, YAxis, Tooltip, Legend, ResponsiveContainer, Cell,
} from 'recharts'
import { getActuals, getScheduled, getNetSales, getBudgets, getDeptDetail, downloadExport } from '../api'
import type { DeptActuals, DeptScheduled, ForecastMethod, WageBudget, EmployeeDetail } from '../types'
import { DeptDetailModal } from '../components/DeptDetailModal'
import { forecastDayCost } from '../lib/forecast'

function fmt(d: Date): string {
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
}
function addDays(d: Date, n: number): Date { const r = new Date(d); r.setDate(r.getDate() + n); return r }
function daysInMonth(y: number, m: number): number { return new Date(y, m, 0).getDate() }
function fmtMoney(n: number): string { return `£${Math.round(n).toLocaleString('en-GB')}` }
function pctClass(pct: number): string { return pct <= 100 ? 'pct-green' : pct <= 110 ? 'pct-amber' : 'pct-red' }
function fmtDelta(pct: number): string { const d = pct - 100; return `${d >= 0 ? '+' : ''}${d.toFixed(1)}%` }
function fmtDisplay(dateStr: string): string {
  return new Date(dateStr + 'T00:00:00').toLocaleDateString('en-GB', { day: 'numeric', month: 'short' })
}
function budgetColour(pct: number): string {
  return pct <= 100 ? 'var(--app-primary)' : pct <= 110 ? '#b45309' : '#dc2626'
}
const DEPT_COLORS = ['#065f46','#059669','#0891b2','#7c3aed','#c2410c','#b45309','#0f766e','#4338ca','#be185d','#15803d']

export default function Monthly() {
  const today        = new Date()
  const todayStr     = fmt(today)
  const yesterdayStr = fmt(addDays(today, -1))
  const todayYear    = parseInt(todayStr.slice(0, 4))
  const todayMonth   = parseInt(todayStr.slice(5, 7))

  const [year,  setYear]  = useState(todayYear)
  const [month, setMonth] = useState(todayMonth)

  const [depts,        setDepts]        = useState<DeptActuals[]>([])
  const [scheduled,    setScheduled]    = useState<DeptScheduled[]>([])
  const [forecastMethod, setForecastMethod] = useState<ForecastMethod>('repeat')
  const [includeUnpublished, setIncludeUnpublished] = useState(false)
  const [netSalesMTD,  setNetSalesMTD]  = useState(0)
  const [netSalesFull, setNetSalesFull] = useState(0)
  const [pySalesMTD,   setPySalesMTD]   = useState(0)
  const [pySalesFull,  setPySalesFull]  = useState(0)
  const [pyWages,      setPyWages]      = useState<number | null>(null)
  const [pyWagesFull,  setPyWagesFull]  = useState<number | null>(null)
  const [pyDepts,      setPyDepts]      = useState<{id: string; name: string; cost: number; costFull: number}[]>([])
  const [pyTableOpen,    setPyTableOpen]    = useState(false)
  const [prevMonthDepts, setPrevMonthDepts] = useState<{id: string; cost: number}[]>([])
  const [budget,         setBudget]         = useState<number | null>(null)
  const [pySalesByDay,   setPySalesByDay]   = useState<Record<string, number>>({})
  const [deptPcts,     setDeptPcts]     = useState<Record<string, number>>({})
  const [showOncosts,  setShowOncosts]  = useState(true)
  const [loading,      setLoading]      = useState(true)
  const [error,        setError]        = useState<string | null>(null)
  const [modal,        setModal]        = useState<{ deptId: string; deptName: string } | null>(null)
  const [modalEmps,    setModalEmps]    = useState<EmployeeDetail[] | null>(null)
  const [modalLoad,    setModalLoad]    = useState(false)

  const dim            = daysInMonth(year, month)
  const monthStr       = `${year}-${String(month).padStart(2, '0')}`
  const fromStr        = `${monthStr}-01`
  const toStr          = `${monthStr}-${String(dim).padStart(2, '0')}`
  const isCurrentMonth = year === todayYear && month === todayMonth

  // forecastDayCost hops back up to 42 days looking for a same-weekday actual — fetch that
  // much extra history before the month start so early-month dates can actually find it,
  // instead of falling through to the 'none' tier once rota runs out. actualMTD/etc. below
  // still filter to >= fromStr, so this extra history is only ever used for the hop fallback.
  const actualsFromStr = fmt(addDays(new Date(fromStr + 'T00:00:00'), -42))

  // Prior year: always fetch full month (derive both MTD and full totals from one call)
  const pyDim     = daysInMonth(year - 1, month)
  const pyFromStr = `${year - 1}-${String(month).padStart(2, '0')}-01`
  const pyToStr   = `${year - 1}-${String(month).padStart(2, '0')}-${String(pyDim).padStart(2, '0')}`

  // Previous month: always fetch full month for comparison
  const pmYear    = month === 1 ? year - 1 : year
  const pmMonth   = month === 1 ? 12 : month - 1
  const pmDim     = daysInMonth(pmYear, pmMonth)
  const pmFromStr = `${pmYear}-${String(pmMonth).padStart(2, '0')}-01`
  const pmToStr   = `${pmYear}-${String(pmMonth).padStart(2, '0')}-${String(pmDim).padStart(2, '0')}`

  const load = useCallback(async () => {
    setLoading(true); setError(null)
    try {
      // Net sales: full month — OTB/forecast for future dates, actuals for past dates
      const [actRes, schedRes, salesRes, budRes, pyActRes, pmActRes] = await Promise.all([
        getActuals(actualsFromStr, toStr),
        getScheduled(fromStr, toStr),
        getNetSales(fromStr, toStr),
        getBudgets(),
        getActuals(pyFromStr, pyToStr),
        getActuals(pmFromStr, pmToStr),
      ])
      setDepts(actRes.departments)
      setScheduled(schedRes.departments)
      setShowOncosts(actRes.show_oncosts)
      setDeptPcts(actRes.dept_pcts)
      setForecastMethod(actRes.forecast_method)

      // Cut-off for MTD = yesterday (avoid partial clockins today)
      const cutoff = isCurrentMonth ? yesterdayStr : toStr

      setNetSalesMTD(salesRes.days.filter(d => d.date <= cutoff).reduce((s, d) => s + d.net_sales, 0))
      setNetSalesFull(salesRes.days.reduce((s, d) => s + d.net_sales, 0))
      setPySalesMTD(salesRes.days.filter(d => d.date <= cutoff).reduce((s, d) => s + d.py_sales, 0))
      setPySalesFull(salesRes.days.reduce((s, d) => s + d.py_sales, 0))

      const pyMap: Record<string, number> = {}
      for (const d of salesRes.days) pyMap[d.date] = d.py_sales
      setPySalesByDay(pyMap)

      // PY MTD: same day number as yesterday in PY (or full month for past months)
      const yDay       = parseInt(yesterdayStr.slice(8))
      const pyMtdLimit = isCurrentMonth
        ? `${year - 1}-${String(month).padStart(2, '0')}-${String(Math.min(yDay, pyDim)).padStart(2, '0')}`
        : pyToStr

      const pyDeptList = pyActRes.departments.map(dep => {
        const mtdCost  = Object.entries(dep.days).filter(([d]) => d <= pyMtdLimit).reduce((s, [, v]) => s + v.cost, 0)
        const fullCost = Object.values(dep.days).reduce((s, v) => s + v.cost, 0)
        return { id: dep.department_id, name: dep.department_name, cost: mtdCost, costFull: fullCost }
      }).filter(d => d.cost > 0 || d.costFull > 0).sort((a, b) => b.costFull - a.costFull)
      setPyDepts(pyDeptList)
      const pyTotalMTD  = pyDeptList.reduce((s, d) => s + d.cost, 0)
      const pyTotalFull = pyDeptList.reduce((s, d) => s + d.costFull, 0)
      setPyWages(pyTotalMTD > 0 ? pyTotalMTD : null)
      setPyWagesFull(pyTotalFull > 0 ? pyTotalFull : null)

      const bRow = budRes.budgets.find((b: WageBudget) => b.month === fromStr)
      setBudget(bRow ? bRow.budget_amount : null)

      // Previous month per-dept totals (full month) for vs Prev column
      const pmDeptList = pmActRes.departments.map(dep => ({
        id:   dep.department_id,
        cost: Object.values(dep.days).reduce((s, v) => s + v.cost, 0),
      }))
      setPrevMonthDepts(pmDeptList)
    } catch (e: unknown) {
      setError(e instanceof Error ? e.message : 'Failed to load')
    } finally {
      setLoading(false)
    }
  }, [fromStr, toStr, actualsFromStr, pyFromStr, pyToStr, pmFromStr, pmToStr, isCurrentMonth, yesterdayStr, year, month, pyDim])

  useEffect(() => { load() }, [load])

  useEffect(() => {
    if (!modal) { setModalEmps(null); return }
    setModalLoad(true)
    getDeptDetail(modal.deptId, fromStr, isCurrentMonth ? yesterdayStr : toStr)
      .then(r => setModalEmps(r.employees))
      .catch(() => setModalEmps([]))
      .finally(() => setModalLoad(false))
  }, [modal, fromStr, toStr, yesterdayStr, isCurrentMonth])

  const prev = () => { if (month === 1) { setYear(y => y - 1); setMonth(12) } else { setMonth(m => m - 1) } }
  const next = () => { if (month === 12) { setYear(y => y + 1); setMonth(1) } else { setMonth(m => m + 1) } }

  // Actuals cut off at yesterday; remaining days forecast via prior-week same-day actual
  const cutoff = isCurrentMonth ? yesterdayStr : toStr

  const deptSummary = depts.map((dep, idx) => {
    const actualMTD = Object.entries(dep.days)
      .filter(([d]) => d >= fromStr && d <= cutoff)
      .reduce((s, [, v]) => s + v.cost, 0)

    let forecastRem = 0
    if (isCurrentMonth) {
      // 'rota' method: prefer published rota (or +draft rota if includeUnpublished) for days
      // that have it, falling back to the repeat-pattern otherwise — see forecastDayCost.
      // 'repeat' (default): unchanged, no scheduled data passed in so it always repeats.
      const schedDep = forecastMethod === 'rota' ? scheduled.find(s => s.department_id === dep.department_id) : undefined
      for (let day = 1; day <= dim; day++) {
        const dateStr = `${monthStr}-${String(day).padStart(2, '0')}`
        if (dateStr <= yesterdayStr) continue
        forecastRem += forecastDayCost(dateStr, dep.days, schedDep?.days, includeUnpublished).cost
      }
    }

    return {
      department_id:   dep.department_id,
      department_name: dep.department_name,
      actual_mtd:      actualMTD,
      forecast_eom:    actualMTD + forecastRem,
      color:           DEPT_COLORS[idx % DEPT_COLORS.length],
    }
  }).sort((a, b) => b.forecast_eom - a.forecast_eom)

  const totalActual      = deptSummary.reduce((s, d) => s + d.actual_mtd, 0)
  const totalForecast    = deptSummary.reduce((s, d) => s + d.forecast_eom, 0)
  const pyTotalWages     = pyDepts.reduce((s, d) => s + d.cost, 0)
  const pyTotalWagesFull = pyDepts.reduce((s, d) => s + d.costFull, 0)
  const prevMonthTotal   = prevMonthDepts.reduce((s, d) => s + d.cost, 0)

  // MTD row: budget split across the month by each day's share of PY (DOW-matched) sales,
  // so a weekend-heavy budget lands more on weekends rather than an even calendar split.
  // Falls back to flat day-count proration when PY sales data isn't available.
  const yDay          = isCurrentMonth ? parseInt(yesterdayStr.slice(8)) : dim
  const monthPyTotal  = Object.values(pySalesByDay).reduce((s, v) => s + v, 0)
  const isBudgetWeighted = monthPyTotal > 0
  const mtdFrac = isBudgetWeighted
    ? Object.entries(pySalesByDay).filter(([d]) => d <= cutoff).reduce((s, [, v]) => s + v, 0) / monthPyTotal
    : yDay / dim
  const budgetMTD    = budget != null ? budget * mtdFrac : null
  const varianceMTD  = budgetMTD != null ? totalActual - budgetMTD : null
  const pctBudgMTD   = budgetMTD != null && budgetMTD > 0 ? (totalActual / budgetMTD) * 100 : null
  const pctSalesMTD  = netSalesMTD > 0 ? (totalActual / netSalesMTD) * 100 : null

  // Full month row
  const varianceFull  = budget != null ? totalForecast - budget : null
  const pctBudgFull   = budget != null && budget > 0 ? (totalForecast / budget) * 100 : null
  const pctSalesFull  = netSalesFull > 0 ? (totalForecast / netSalesFull) * 100 : null

  function pyPct(current: number, py: number): string {
    if (py <= 0 || current <= 0) return ''
    const p = ((current - py) / py) * 100
    return ` (${p >= 0 ? '+' : ''}${p.toFixed(1)}%)`
  }

  // Chart: past weeks solid, current/future weeks lighter
  type WeekEntry = { label: string; isPast: boolean; [dept: string]: number | boolean | string }
  const weeks: WeekEntry[] = []
  for (let w = 0; w * 7 < dim; w++) {
    const wStart  = w * 7 + 1
    const wEnd    = Math.min(wStart + 6, dim)
    const wEndStr = `${monthStr}-${String(wEnd).padStart(2, '0')}`
    const isPast  = wEndStr <= yesterdayStr

    const entry: WeekEntry = { label: `W${w + 1}`, isPast }
    for (const dep of deptSummary) {
      const srcDep   = depts.find(d => d.department_id === dep.department_id)
      const schedDep = forecastMethod === 'rota' ? scheduled.find(s => s.department_id === dep.department_id) : undefined
      let deptCost = 0
      let weekTier: 'rota' | 'repeat' = 'rota'
      for (let day = wStart; day <= wEnd; day++) {
        const dateStr = `${monthStr}-${String(day).padStart(2, '0')}`
        if (dateStr <= cutoff) {
          deptCost += srcDep?.days[dateStr]?.cost ?? 0
        } else {
          const { cost, tier } = forecastDayCost(dateStr, srcDep?.days, schedDep?.days, includeUnpublished)
          deptCost += cost
          if (tier === 'actual' || tier === 'none') weekTier = 'repeat'
        }
      }
      entry[dep.department_name] = deptCost
      entry[`${dep.department_name}__tier`] = weekTier
    }
    weeks.push(entry)
  }

  const monthLabel = new Date(year, month - 1, 1).toLocaleDateString('en-GB', { month: 'long', year: 'numeric' })

  return (
    <div>
      <div className="page-header">
        <h1 className="page-title">Monthly View</h1>
        <button className="btn btn-secondary" onClick={() => downloadExport('monthly', fromStr, toStr)}>
          <Download size={14} strokeWidth={1.75} /> CSV
        </button>
      </div>

      <div className="period-nav" style={{ marginBottom: 20 }}>
        <button className="btn btn-secondary" onClick={prev}><ChevronLeft size={16} strokeWidth={1.75} /></button>
        <span className="period-label">{monthLabel}</span>
        <button className="btn btn-secondary" onClick={next} disabled={isCurrentMonth}><ChevronRight size={16} strokeWidth={1.75} /></button>
      </div>

      {/* ── Summary cards ─────────────────────────────────────────── */}
      {isCurrentMonth ? (
        <>
          <div className="section-row-label">Month to {fmtDisplay(yesterdayStr)}</div>
          <div className="summary-grid" style={{ marginBottom: 8 }}>
            <div className="summary-card">
              <div className="label">Actual MTD</div>
              <div className="value">{fmtMoney(totalActual)}</div>
              {pyWages != null && <div className="sub">PY MTD {fmtMoney(pyWages)}{pyPct(totalActual, pyWages)}</div>}
            </div>
            <div className="summary-card">
              <div className="label">Budget MTD</div>
              <div className="value">{budgetMTD != null ? fmtMoney(budgetMTD) : '—'}</div>
              <div className="sub">{isBudgetWeighted ? 'sales-weighted (PY DOW)' : `pro-rata ${yDay}/${dim} days`}</div>
            </div>
            <div className="summary-card">
              <div className="label">% Budget MTD</div>
              <div className="value" style={pctBudgMTD != null ? { color: budgetColour(pctBudgMTD) } : {}}>
                {pctBudgMTD != null ? fmtDelta(pctBudgMTD) : '—'}
              </div>
              {varianceMTD != null && (
                <div className={`sub ${varianceMTD > 0 ? 'variance-over' : 'variance-under'}`}>
                  {varianceMTD > 0 ? `+${fmtMoney(varianceMTD)} over` : `${fmtMoney(Math.abs(varianceMTD))} under`}
                </div>
              )}
            </div>
            <div className="summary-card">
              <div className="label">% Net Sales MTD</div>
              <div className="value">{pctSalesMTD != null ? `${pctSalesMTD.toFixed(1)}%` : '—'}</div>
              {pyWages != null && pySalesMTD > 0 && (
                <div className="sub">PY MTD {((pyWages / pySalesMTD) * 100).toFixed(1)}%</div>
              )}
            </div>
            <div className="summary-card">
              <div className="label">Net Sales MTD</div>
              <div className="value">{fmtMoney(netSalesMTD)}</div>
              {pySalesMTD > 0 && <div className="sub">PY {fmtMoney(pySalesMTD)}{pyPct(netSalesMTD, pySalesMTD)}</div>}
            </div>
          </div>

          <div className="section-row-label" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <span>Full month forecast</span>
            {forecastMethod === 'rota' && (
              <label
                style={{ display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer', fontSize: 12, fontWeight: 400, color: 'var(--text-muted)' }}
                title="Only affects days with zero published shifts so far — those days use draft rota cost instead of falling back to a repeated estimate. A day with at least one published shift already uses that day's own rota cost (plus draft cost too, if this is checked) — it never blends with, or falls back to, a repeated day."
              >
                <input type="checkbox" checked={includeUnpublished} onChange={e => setIncludeUnpublished(e.target.checked)} />
                Include unpublished shifts in forecast
              </label>
            )}
          </div>
          <div className="summary-grid" style={{ marginBottom: 20 }}>
            <div className="summary-card">
              <div className="label">Forecast EOM</div>
              <div className="value">{fmtMoney(totalForecast)}</div>
              {pyWagesFull != null && <div className="sub">PY {fmtMoney(pyWagesFull)}{pyPct(totalForecast, pyWagesFull)}</div>}
            </div>
            <div className="summary-card">
              <div className="label">Monthly Budget</div>
              <div className="value">{budget != null ? fmtMoney(budget) : '—'}</div>
            </div>
            <div className="summary-card">
              <div className="label">% Budget (Forecast)</div>
              <div className="value" style={pctBudgFull != null ? { color: budgetColour(pctBudgFull) } : {}}>
                {pctBudgFull != null ? fmtDelta(pctBudgFull) : '—'}
              </div>
              {varianceFull != null && (
                <div className={`sub ${varianceFull > 0 ? 'variance-over' : 'variance-under'}`}>
                  {varianceFull > 0 ? `+${fmtMoney(varianceFull)} over` : `${fmtMoney(Math.abs(varianceFull))} under`}
                </div>
              )}
            </div>
            <div className="summary-card">
              <div className="label">% Net Sales (Forecast)</div>
              <div className="value">{pctSalesFull != null ? `${pctSalesFull.toFixed(1)}%` : '—'}</div>
              {pyWagesFull != null && pySalesFull > 0 && (
                <div className="sub">PY {((pyWagesFull / pySalesFull) * 100).toFixed(1)}%</div>
              )}
            </div>
            <div className="summary-card">
              <div className="label">Net Sales (Forecast)</div>
              <div className="value">{fmtMoney(netSalesFull)}</div>
              {pySalesFull > 0 && <div className="sub">PY {fmtMoney(pySalesFull)}{pyPct(netSalesFull, pySalesFull)}</div>}
            </div>
          </div>
        </>
      ) : (
        <div className="summary-grid" style={{ marginBottom: 20 }}>
          <div className="summary-card">
            <div className="label">Actual</div>
            <div className="value">{fmtMoney(totalActual)}</div>
            {pyWagesFull != null && <div className="sub">PY {fmtMoney(pyWagesFull)}{pyPct(totalActual, pyWagesFull)}</div>}
          </div>
          <div className="summary-card">
            <div className="label">Monthly Budget</div>
            <div className="value">{budget != null ? fmtMoney(budget) : '—'}</div>
          </div>
          <div className="summary-card">
            <div className="label">% Budget</div>
            <div className="value" style={pctBudgFull != null ? { color: budgetColour(pctBudgFull) } : {}}>
              {pctBudgFull != null ? fmtDelta(pctBudgFull) : '—'}
            </div>
            {varianceFull != null && (
              <div className={`sub ${varianceFull > 0 ? 'variance-over' : 'variance-under'}`}>
                {varianceFull > 0 ? `+${fmtMoney(varianceFull)} over` : `${fmtMoney(Math.abs(varianceFull))} under`}
              </div>
            )}
          </div>
          <div className="summary-card">
            <div className="label">% Net Sales</div>
            <div className="value">{pctSalesFull != null ? `${pctSalesFull.toFixed(1)}%` : '—'}</div>
            {pyWagesFull != null && pySalesFull > 0 && (
              <div className="sub">PY {((pyWagesFull / pySalesFull) * 100).toFixed(1)}%</div>
            )}
          </div>
          <div className="summary-card">
            <div className="label">Net Sales</div>
            <div className="value">{fmtMoney(netSalesFull)}</div>
            {pySalesFull > 0 && <div className="sub">PY {fmtMoney(pySalesFull)}{pyPct(netSalesFull, pySalesFull)}</div>}
          </div>
        </div>
      )}

      {loading && <div className="state-center">Loading…</div>}
      {error   && <div className="state-center" style={{ color: '#dc2626' }}>{error}</div>}

      {!loading && !error && (
        <>
          <div className="card">
            <div className="card-title">
              Weekly Breakdown{isCurrentMonth ? (forecastMethod === 'rota' ? ' (rota-informed forecast shaded, repeat-pattern lighter)' : ' (forecast shaded)') : ''}
            </div>
            <ResponsiveContainer width="100%" height={260}>
              <BarChart data={weeks} margin={{ top: 4, right: 16, left: 16, bottom: 0 }}>
                <XAxis dataKey="label" tick={{ fontSize: 12 }} />
                <YAxis tickFormatter={v => `£${Math.round(Number(v) / 1000)}k`} tick={{ fontSize: 11 }} width={55} />
                <Tooltip formatter={(v: unknown) => fmtMoney(Number(v))} />
                <Legend itemSorter={item => -deptSummary.findIndex(dep => dep.department_name === item.dataKey)} />
                {deptSummary.map(dep => (
                  <Bar key={dep.department_id} dataKey={dep.department_name} stackId="a" fill={dep.color}>
                    {weeks.map((w, i) => {
                      const opacity = w.isPast ? 1 : (w[`${dep.department_name}__tier`] === 'rota' ? 0.7 : 0.45)
                      return <Cell key={i} fill={dep.color} opacity={opacity} />
                    })}
                  </Bar>
                ))}
              </BarChart>
            </ResponsiveContainer>
          </div>

          <div className="card">
            <table className="data-table">
              <thead>
                <tr>
                  <th>Department</th>
                  <th className="right">{isCurrentMonth ? 'Actual MTD' : 'Actual'}</th>
                  {isCurrentMonth && <th className="right">Forecast → EOM</th>}
                  <th className="right">% of Total</th>
                  <th className="right">vs PY</th>
                  <th className="right">vs Prev</th>
                  <th className="right">Budget</th>
                  <th className="right">% Budget</th>
                  <th className="right">Variance</th>
                </tr>
              </thead>
              <tbody>
                {deptSummary.map(dep => {
                  const displayCost  = isCurrentMonth ? dep.forecast_eom : dep.actual_mtd
                  const totalDisplay = isCurrentMonth ? totalForecast : totalActual
                  const depBudg = budget != null && (deptPcts[dep.department_id] ?? 0) > 0
                    ? budget * (deptPcts[dep.department_id] / 100)
                    : null
                  const dp         = depBudg != null && depBudg > 0 ? (displayCost / depBudg) * 100 : null
                  const dv         = depBudg != null ? displayCost - depBudg : null
                  const depOfTotal = totalDisplay > 0 ? (displayCost / totalDisplay) * 100 : null
                  // PY: compare actual_mtd vs PY MTD for current month; actual vs PY full for past months
                  const pyDept   = pyDepts.find(p => p.id === dep.department_id)
                  const pyCost   = pyDept ? (isCurrentMonth ? pyDept.cost : pyDept.costFull) : null
                  const pyDelta  = pyCost != null && pyCost > 0 ? ((dep.actual_mtd - pyCost) / pyCost) * 100 : null
                  // Prev month: compare actual_mtd vs prev month full total per dept
                  const pmDept   = prevMonthDepts.find(p => p.id === dep.department_id)
                  const pmCost   = pmDept && pmDept.cost > 0 ? pmDept.cost : null
                  const pmDelta  = pmCost != null ? ((dep.actual_mtd - pmCost) / pmCost) * 100 : null
                  return (
                    <tr key={dep.department_id} style={{ cursor: 'pointer' }}
                        onClick={() => setModal({ deptId: dep.department_id, deptName: dep.department_name })}>
                      <td>
                        <span style={{ display: 'inline-block', width: 10, height: 10, borderRadius: '50%', background: dep.color, marginRight: 8 }} />
                        {dep.department_name}
                      </td>
                      <td className="right">{fmtMoney(dep.actual_mtd)}</td>
                      {isCurrentMonth && <td className="right">{fmtMoney(dep.forecast_eom)}</td>}
                      <td className="right" style={{ color: 'var(--text-muted)' }}>
                        {depOfTotal != null ? `${depOfTotal.toFixed(1)}%` : '—'}
                      </td>
                      <td className="right">
                        {pyDelta != null
                          ? <span className={pyDelta > 0 ? 'variance-over' : 'variance-under'}>{pyDelta > 0 ? '+' : ''}{pyDelta.toFixed(1)}%</span>
                          : '—'}
                      </td>
                      <td className="right">
                        {pmDelta != null
                          ? <span className={pmDelta > 0 ? 'variance-over' : 'variance-under'}>{pmDelta > 0 ? '+' : ''}{pmDelta.toFixed(1)}%</span>
                          : '—'}
                      </td>
                      <td className="right">{depBudg != null ? fmtMoney(depBudg) : '—'}</td>
                      <td className="right">
                        {dp != null ? <span className={`pct-badge ${pctClass(dp)}`}>{fmtDelta(dp)}</span> : '—'}
                      </td>
                      <td className="right">
                        {dv != null && <span className={dv > 0 ? 'variance-over' : 'variance-under'}>{dv > 0 ? '+' : ''}{fmtMoney(dv)}</span>}
                      </td>
                    </tr>
                  )
                })}
                <tr className="total-row">
                  <td>Total</td>
                  <td className="right">{fmtMoney(totalActual)}</td>
                  {isCurrentMonth && <td className="right">{fmtMoney(totalForecast)}</td>}
                  <td className="right">100%</td>
                  <td className="right">
                    {(() => {
                      const pyBase = isCurrentMonth ? pyTotalWages : pyTotalWagesFull
                      if (pyBase <= 0) return '—'
                      const d = ((totalActual - pyBase) / pyBase) * 100
                      return <span className={d > 0 ? 'variance-over' : 'variance-under'}>{d > 0 ? '+' : ''}{d.toFixed(1)}%</span>
                    })()}
                  </td>
                  <td className="right">
                    {(() => {
                      if (prevMonthTotal <= 0) return '—'
                      const d = ((totalActual - prevMonthTotal) / prevMonthTotal) * 100
                      return <span className={d > 0 ? 'variance-over' : 'variance-under'}>{d > 0 ? '+' : ''}{d.toFixed(1)}%</span>
                    })()}
                  </td>
                  <td className="right">{budget != null ? fmtMoney(budget) : '—'}</td>
                  <td className="right">
                    {pctBudgFull != null ? <span className={`pct-badge ${pctClass(pctBudgFull)}`}>{fmtDelta(pctBudgFull)}</span> : '—'}
                  </td>
                  <td className="right">
                    {varianceFull != null && <span className={varianceFull > 0 ? 'variance-over' : 'variance-under'}>{varianceFull > 0 ? '+' : ''}{fmtMoney(varianceFull)}</span>}
                  </td>
                </tr>
              </tbody>
            </table>
            {showOncosts && <p className="footnote">Includes estimated employer on-costs. Final payroll figures are in Sage.</p>}
          </div>

          {pyDepts.length > 0 && (
            <div className="card">
              <button className="py-collapse-toggle" onClick={() => setPyTableOpen(o => !o)}>
                {pyTableOpen
                  ? <ChevronDown size={14} strokeWidth={1.75} />
                  : <ChevronRight size={14} strokeWidth={1.75} />}
                {isCurrentMonth ? 'PY MTD' : 'PY'} Dept Breakdown ({pyFromStr.slice(0, 7)})
              </button>
              {pyTableOpen && (
                <table className="data-table" style={{ marginTop: 12 }}>
                  <thead>
                    <tr>
                      <th>Department</th>
                      <th className="right">{isCurrentMonth ? 'PY MTD' : 'PY'} Wages</th>
                      <th className="right">% of Total</th>
                      <th className="right">% Net Sales</th>
                    </tr>
                  </thead>
                  <tbody>
                    {pyDepts.map(dep => {
                      const ofTotal = pyTotalWages > 0 ? (dep.cost / pyTotalWages) * 100 : null
                      const ofSales = pySalesMTD > 0 ? (dep.cost / pySalesMTD) * 100 : null
                      return (
                        <tr key={dep.id}>
                          <td>{dep.name}</td>
                          <td className="right">{fmtMoney(dep.cost)}</td>
                          <td className="right" style={{ color: 'var(--text-muted)' }}>{ofTotal != null ? `${ofTotal.toFixed(1)}%` : '—'}</td>
                          <td className="right">{ofSales != null ? `${ofSales.toFixed(1)}%` : '—'}</td>
                        </tr>
                      )
                    })}
                    <tr className="total-row">
                      <td>Total</td>
                      <td className="right">{fmtMoney(pyTotalWages)}</td>
                      <td className="right">100%</td>
                      <td className="right">{pySalesMTD > 0 ? `${((pyTotalWages / pySalesMTD) * 100).toFixed(1)}%` : '—'}</td>
                    </tr>
                  </tbody>
                </table>
              )}
            </div>
          )}
        </>
      )}

      {modal && (
        <DeptDetailModal
          deptName={modal.deptName}
          period={isCurrentMonth ? `MTD to ${fmtDisplay(yesterdayStr)}` : monthLabel}
          employees={modalEmps}
          loading={modalLoad}
          onClose={() => setModal(null)}
        />
      )}
    </div>
  )
}
