// Dashboard.jsx
function StatCard({ icon, iconKind, label, value, delta, deltaDir }) {
  const Ico = window[icon];
  return (
    <div className="stat-card">
      <div className="stat-card__head">
        <div className={"stat-card__icon stat-card__icon--" + (iconKind || '')}><Ico size={20}/></div>
        {delta ? (
          <div className={"stat-card__delta stat-card__delta--" + (deltaDir || 'up')}>
            {deltaDir === 'down' ? <TrendDown size={12}/> : <TrendUp size={12}/>}
            {delta}
          </div>
        ) : null}
      </div>
      <div className="stat-card__label">{label}</div>
      <div className="stat-card__value">{value}</div>
    </div>
  );
}

function QABtn({ icon, title, sub, onClick, primary }) {
  const Ico = window[icon];
  return (
    <button className="qa-btn" onClick={onClick}>
      <div className={"qa-btn__icon " + (primary ? '' : 'qa-btn__icon--navy')}><Ico size={18}/></div>
      <div>
        <div className="qa-btn__title">{title}</div>
        <div className="qa-btn__sub">{sub}</div>
      </div>
    </button>
  );
}

function MiniBarChart() {
  const data = [
    { day: 'Mon', v: 6 }, { day: 'Tue', v: 8 }, { day: 'Wed', v: 5 },
    { day: 'Thu', v: 9 }, { day: 'Fri', v: 11, accent: true }, { day: 'Sat', v: 7 }, { day: 'Sun', v: 3 },
  ];
  const max = Math.max(...data.map(d => d.v));
  return (
    <div className="chart-bar">
      {data.map(d => (
        <div className="chart-bar__col" key={d.day}>
          <div className="chart-bar__bar-wrap">
            <div className={"chart-bar__bar " + (d.accent ? 'chart-bar__bar--accent' : '')}
              style={{height: (d.v / max * 100) + '%'}} title={d.v + ' jobs'}/>
          </div>
          <div className="chart-bar__label">{d.day}</div>
        </div>
      ))}
    </div>
  );
}

// ===== Highest Earning Crane ============================================
// "What's happening now": which machine has generated the most completed-job
// revenue this calendar month. If too few jobs are completed early in the
// month (<5), fall back to a rolling last-30-days window instead.
const _parseRM = (s) => Number(String(s || '').replace(/[^0-9.]/g, '')) || 0;
const _fmtMoney = (n) => 'RM ' + Math.round(n).toLocaleString('en-MY');
const _ymd = (d) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
const _addDays = (iso, n) => { const d = new Date(iso + 'T12:00:00'); d.setDate(d.getDate() + n); return _ymd(d); };
const _firstOfMonth = (iso) => iso.slice(0, 7) + '-01';
const _lastOfMonth = (iso) => { const d = new Date(iso + 'T12:00:00'); return _ymd(new Date(d.getFullYear(), d.getMonth() + 1, 0)); };

// Plate as stored on bookings (short) → full registration plate from master.
const _machineForPlate = (plate) => MACHINES.find(x => x.plate && x.plate.split(' ').pop() === String(plate)) || null;
const _fullPlate = (plate) => { const m = _machineForPlate(plate); return m ? m.plate : plate; };

// Unique completed jobs — dedupe multi-day rows by booking id so a single
// booking's price isn't counted once per day. Attribute to its end date.
function _completedJobs() {
  const seen = {};
  BOOKINGS.forEach(b => {
    if (b.status !== 'Job Completed') return;
    if (!seen[b.id]) seen[b.id] = { plate: b.plate || '—', revenue: _parseRM(b.price), date: b.dateTo || b.date };
  });
  return Object.values(seen);
}
function _earningsByCrane(jobs, startISO, endISO) {
  const m = {};
  jobs.forEach(j => {
    if (j.date < startISO || j.date > endISO) return;
    if (!m[j.plate]) m[j.plate] = { plate: j.plate, revenue: 0, jobs: 0 };
    m[j.plate].revenue += j.revenue;
    m[j.plate].jobs += 1;
  });
  return Object.values(m).sort((a, b) => b.revenue - a.revenue);
}
function computeHighestEarner() {
  const jobs = _completedJobs();
  const monthStart = _firstOfMonth(TODAY);
  const monthRows = _earningsByCrane(jobs, monthStart, TODAY);
  const monthJobCount = monthRows.reduce((a, c) => a + c.jobs, 0);
  const useMonth = monthJobCount >= 5;

  let curStart, curEnd, prevStart, prevEnd, periodLabel, compareLabel;
  if (useMonth) {
    curStart = monthStart; curEnd = TODAY;
    prevStart = _firstOfMonth(_addDays(monthStart, -1));
    prevEnd = _lastOfMonth(prevStart);
    periodLabel = 'this month';
    compareLabel = 'vs last month';
  } else {
    curStart = _addDays(TODAY, -29); curEnd = TODAY;
    prevStart = _addDays(TODAY, -59); prevEnd = _addDays(TODAY, -30);
    periodLabel = 'last 30 days';
    compareLabel = 'vs prior 30 days';
  }
  const cur = _earningsByCrane(jobs, curStart, curEnd);
  const prevByPlate = Object.fromEntries(_earningsByCrane(jobs, prevStart, prevEnd).map(r => [r.plate, r.revenue]));
  const winner = cur[0] || null;
  let deltaPct = null, deltaDir = 'up';
  if (winner) {
    const p = prevByPlate[winner.plate] || 0;
    if (p > 0) { deltaPct = Math.round((winner.revenue - p) / p * 100); deltaDir = deltaPct >= 0 ? 'up' : 'down'; }
  }
  return { useMonth, periodLabel, compareLabel, winner, top5: cur.slice(0, 5), deltaPct, deltaDir };
}

function HighestEarnerCard({ info, onOpen }) {
  const { winner, periodLabel, compareLabel, deltaPct, deltaDir } = info;
  const plate = winner ? _fullPlate(winner.plate) : '—';
  const mac = winner ? _machineForPlate(winner.plate) : null;
  const rev = winner ? winner.revenue : 0;
  const Trend = deltaDir === 'down' ? TrendDown : TrendUp;
  return (
    <button type="button" className="stat-card stat-card--action" onClick={onOpen}>
      <div className="stat-card__head">
        <div className="stat-card__icon stat-card__icon--yellow"><DollarSign size={20}/></div>
        {deltaPct !== null ? (
          <div className={"stat-card__delta stat-card__delta--" + deltaDir}>
            <Trend size={12}/>{deltaPct >= 0 ? '+' : '−'}{Math.abs(deltaPct)}% {compareLabel}
          </div>
        ) : winner ? (
          <div className="stat-card__delta" style={{color: 'var(--color-grey-400)'}}>New top earner</div>
        ) : null}
      </div>
      <div className="stat-card__label">Highest Earning Crane</div>
      <div className="stat-card__value" style={{fontSize: 26, marginBottom: 6}}>{plate}</div>
      <div style={{fontSize: 13, color: 'var(--color-grey-600)', display: 'flex', alignItems: 'baseline', gap: 6, flexWrap: 'wrap'}}>
        <span style={{fontWeight: 700, color: 'var(--color-navy)'}}>{_fmtMoney(rev)}</span>
        <span style={{color: 'var(--color-grey-500)'}}>{periodLabel}</span>
      </div>
      {mac ? <div style={{fontSize: 12, color: 'var(--color-grey-400)', marginTop: 4}}>{machineLabel(mac)}</div> : null}
      <span className="stat-card__more">Top 5 <ChevRight size={12}/></span>
    </button>
  );
}

function TopEarnersModal({ info, onClose }) {
  const { top5, periodLabel } = info;
  const max = top5.length ? top5[0].revenue : 1;
  return (
    <div className="install-modal" onClick={onClose}>
      <div className="install-modal__card" onClick={e => e.stopPropagation()} style={{maxWidth: 540, width: '94vw'}}>
        <div style={{display: 'flex', alignItems: 'center', gap: 12, marginBottom: 18}}>
          <div style={{width: 44, height: 44, borderRadius: 10, background: 'var(--color-navy)', display: 'grid', placeItems: 'center', color: 'var(--color-yellow)', flexShrink: 0}}>
            <DollarSign size={20}/>
          </div>
          <div style={{flex: 1, minWidth: 0}}>
            <div style={{fontWeight: 700, fontSize: 17, color: 'var(--color-navy)'}}>Top 5 Earning Cranes</div>
            <div style={{fontSize: 12, color: 'var(--color-grey-500)', marginTop: 2}}>Completed-job revenue · {periodLabel}</div>
          </div>
          <button type="button" className="install-banner__close" onClick={onClose}><X size={18}/></button>
        </div>
        <div style={{display: 'flex', flexDirection: 'column', gap: 12}}>
          {top5.map((r, i) => {
            const mac = _machineForPlate(r.plate);
            return (
              <div key={r.plate + i} style={{display: 'flex', alignItems: 'center', gap: 12}}>
                <div style={{width: 24, height: 24, borderRadius: '50%', background: i === 0 ? 'var(--color-yellow)' : 'var(--color-grey-100)', color: i === 0 ? 'var(--color-navy)' : 'var(--color-grey-600)', display: 'grid', placeItems: 'center', fontWeight: 700, fontSize: 12, flexShrink: 0}}>{i + 1}</div>
                <div style={{flex: 1, minWidth: 0}}>
                  <div style={{display: 'flex', justifyContent: 'space-between', gap: 10}}>
                    <span style={{fontWeight: 700, color: 'var(--color-navy)', fontFamily: 'var(--font-mono)'}}>{_fullPlate(r.plate)}</span>
                    <span style={{fontWeight: 700, color: 'var(--color-navy)', whiteSpace: 'nowrap'}}>{_fmtMoney(r.revenue)}</span>
                  </div>
                  <div style={{height: 6, borderRadius: 3, background: 'var(--color-grey-100)', marginTop: 6, overflow: 'hidden'}}>
                    <div style={{height: '100%', width: (r.revenue / max * 100) + '%', background: i === 0 ? 'var(--color-yellow-700)' : 'var(--color-navy)', borderRadius: 3}}/>
                  </div>
                  <div style={{fontSize: 12, color: 'var(--color-grey-500)', marginTop: 4}}>{mac ? machineLabel(mac) : 'Cross-rented'} · {r.jobs} completed job{r.jobs === 1 ? '' : 's'}</div>
                </div>
              </div>
            );
          })}
          {top5.length === 0 ? <div style={{fontSize: 13, color: 'var(--color-grey-400)', fontStyle: 'italic'}}>No completed jobs in this period.</div> : null}
        </div>
      </div>
    </div>
  );
}

// ===== Jobs This Month & Top Crane Type ================================
// Workload (not just completed work): count every BOOKED booking whose
// job_date falls in the current calendar month. "Booked" = anything that
// isn't Cancelled. Dedupe by booking id so multi-day rows count once, and
// attribute the booking to its start date.
const _BOOKED_OUT = new Set(['Cancelled']);
function _bookedJobs() {
  const seen = {};
  BOOKINGS.forEach(b => {
    if (_BOOKED_OUT.has(b.status)) return;
    if (!seen[b.id]) seen[b.id] = { id: b.id, date: b.date, category: b.category || '—', tonnage: b.tonnage || '' };
  });
  return Object.values(seen);
}
function _countInMonth(jobs, startISO, endISO) {
  return jobs.filter(j => j.date >= startISO && j.date <= endISO).length;
}
function computeJobsThisMonth() {
  const jobs = _bookedJobs();
  const monthStart = _firstOfMonth(TODAY);
  const monthEnd = _lastOfMonth(TODAY);
  const prevStart = _firstOfMonth(_addDays(monthStart, -1));
  const prevEnd = _lastOfMonth(prevStart);
  const cur = _countInMonth(jobs, monthStart, monthEnd);
  const prev = _countInMonth(jobs, prevStart, prevEnd);
  let deltaPct = null, deltaDir = 'up';
  if (prev > 0) { deltaPct = Math.round((cur - prev) / prev * 100); deltaDir = deltaPct >= 0 ? 'up' : 'down'; }
  return { cur, prev, deltaPct, deltaDir };
}
// Pretty tonnage/size: '50t' → '50T', '20m' → '20M', '—' stays.
const _fmtSize = (s) => String(s || '').replace(/t$/i, 'T').replace(/m$/i, 'M');
function computeTopCraneType() {
  const jobs = _bookedJobs();
  const monthStart = _firstOfMonth(TODAY);
  const monthEnd = _lastOfMonth(TODAY);
  const counts = {};
  jobs.forEach(j => {
    if (j.date < monthStart || j.date > monthEnd) return;
    const size = _fmtSize(j.tonnage);
    const key = j.category + (size && size !== '—' ? '||' + size : '');
    if (!counts[key]) counts[key] = { category: j.category, size: (size && size !== '—') ? size : '', jobs: 0 };
    counts[key].jobs += 1;
  });
  const ranked = Object.values(counts).sort((a, b) => b.jobs - a.jobs);
  return { top: ranked[0] || null, ranked };
}

function TopCraneTypeCard({ info, monthLabel }) {
  const top = info.top;
  return (
    <div className="stat-card">
      <div className="stat-card__head">
        <div className="stat-card__icon stat-card__icon--blue"><Layers size={20}/></div>
        {top ? <div className="stat-card__delta" style={{color: 'var(--color-grey-400)'}}>Most requested</div> : null}
      </div>
      <div className="stat-card__label">Top Crane Type in Demand</div>
      <div className="stat-card__value" style={{fontSize: 20, marginBottom: 4, lineHeight: 1.2}}>
        {top ? top.category : '—'}
        {top && top.size ? <span style={{color: 'var(--color-yellow-700)'}}> · {top.size}</span> : null}
      </div>
      <div style={{fontSize: 13, color: 'var(--color-grey-600)', display: 'flex', alignItems: 'baseline', gap: 6, flexWrap: 'wrap'}}>
        <span style={{fontWeight: 700, color: 'var(--color-navy)'}}>{top ? top.jobs : 0} job{top && top.jobs === 1 ? '' : 's'}</span>
        <span style={{color: 'var(--color-grey-500)'}}>in {monthLabel}</span>
      </div>
    </div>
  );
}

// ===== Monthly Revenue (card 5) ========================================
// Earned Revenue = sum of price for jobs that are *Job Completed* this
// calendar month, attributed to the completion date. Multi-day rows share
// a booking id and one price, so dedupe by id (via _completedJobs). Trend =
// revenue growth % vs the previous calendar month.
const _fmtMoneyShort = (n) => {
  if (n >= 1000000) return 'RM ' + (n / 1000000).toFixed(n >= 10000000 ? 0 : 1).replace(/\.0$/, '') + 'M';
  if (n >= 1000) return 'RM ' + Math.round(n / 1000) + 'k';
  return 'RM ' + Math.round(n);
};
function computeMonthlyRevenue() {
  const jobs = _completedJobs();
  const monthStart = _firstOfMonth(TODAY);
  const monthEnd = _lastOfMonth(TODAY);
  const prevStart = _firstOfMonth(_addDays(monthStart, -1));
  const prevEnd = _lastOfMonth(prevStart);
  const sumIn = (s, e) => jobs.reduce((a, j) => (j.date >= s && j.date <= e ? a + j.revenue : a), 0);
  const cur = sumIn(monthStart, monthEnd);
  const prev = sumIn(prevStart, prevEnd);
  let deltaPct = null, deltaDir = 'up';
  if (prev > 0) { deltaPct = Math.round((cur - prev) / prev * 100); deltaDir = deltaPct >= 0 ? 'up' : 'down'; }
  return { cur, prev, deltaPct, deltaDir };
}

// ===== Crane Utilization (card 6) ======================================
// Utilization % = booked crane-hours ÷ available crane-hours, over the
// current calendar month.
//   Booked   = Σ(end−start) across every non-cancelled booking row this
//              month. Multi-day bookings store one row per day, so each row
//              correctly contributes that day's hours (no dedupe here).
//   Available= active cranes × working-hours/day × working-days-in-month.
// "Cranes" = the owned lifting fleet (mobile/RT cranes, skylifts, scissor
// lift) — cross-rent units and company cars are excluded. Split out by
// machine type and by individual unit for the drill-down.
const _CRANE_CATS = new Set(['Mobile Crane', 'Rough Terrain Crane', 'Skylift', 'Scissor Lift']);
const HOURS_PER_DAY = 8;
const _hoursOfBooking = (b) => {
  if (!b.start || !b.end) return 0;
  const [sh, sm] = b.start.split(':').map(Number);
  const [eh, em] = b.end.split(':').map(Number);
  return Math.max(0, (eh + (em || 0) / 60) - (sh + (sm || 0) / 60));
};
// Working days = Mon–Sat (Sundays off). Counted from `startISO` through
// `endISO` inclusive — used for month-to-date, so we never divide elapsed
// booked hours by a whole month's capacity mid-month (which would make
// every month look empty until the 30th).
function _workingDaysBetween(startISO, endISO) {
  const d = new Date(startISO + 'T12:00:00');
  let n = 0;
  while (_ymd(d) <= endISO) {
    if (d.getDay() !== 0) n += 1;
    d.setDate(d.getDate() + 1);
  }
  return n;
}
// The Nth working day on/after startISO (for a fair previous-month MTD window).
function _nthWorkingDay(startISO, k) {
  const d = new Date(startISO + 'T12:00:00');
  let n = 0;
  while (true) {
    if (d.getDay() !== 0) { n += 1; if (n === k) return _ymd(d); }
    d.setDate(d.getDate() + 1);
  }
}
function _bookedHoursByMachine(startISO, endISO) {
  const byId = {};
  let total = 0;
  BOOKINGS.forEach(b => {
    if (b.status === 'Cancelled') return;
    if (b.date < startISO || b.date > endISO) return;
    const id = (b.machine || '').split(' ')[0];
    const h = _hoursOfBooking(b);
    if (!h) return;
    byId[id] = (byId[id] || 0) + h;
    total += h;
  });
  return { byId, total };
}
function computeUtilization() {
  const cranes = MACHINES.filter(m => _CRANE_CATS.has(m.category));
  const active = cranes.filter(m => m.status !== 'unavailable');
  const monthStart = _firstOfMonth(TODAY);
  const workingDays = _workingDaysBetween(monthStart, TODAY); // month-to-date
  const availPerCrane = HOURS_PER_DAY * workingDays;
  const totalAvail = active.length * availPerCrane;

  const { byId, total: totalBooked } = _bookedHoursByMachine(monthStart, TODAY);
  const pct = totalAvail > 0 ? Math.round(totalBooked / totalAvail * 100) : 0;

  // By machine type
  const typeMap = {};
  active.forEach(m => {
    if (!typeMap[m.category]) typeMap[m.category] = { category: m.category, booked: 0, count: 0 };
    typeMap[m.category].count += 1;
    typeMap[m.category].booked += byId[m.id] || 0;
  });
  const byType = Object.values(typeMap).map(t => {
    const avail = t.count * availPerCrane;
    return { ...t, avail, pct: avail > 0 ? Math.round(t.booked / avail * 100) : 0 };
  }).sort((a, b) => b.pct - a.pct);

  // By individual unit (active only)
  const byUnit = active.map(m => {
    const booked = byId[m.id] || 0;
    return { machine: m, booked, avail: availPerCrane, pct: availPerCrane > 0 ? Math.round(booked / availPerCrane * 100) : 0 };
  }).sort((a, b) => b.pct - a.pct);

  // Previous-month utilization over the SAME number of working days, for a
  // like-for-like trend.
  const prevStart = _firstOfMonth(_addDays(monthStart, -1));
  const prevEnd = _nthWorkingDay(prevStart, workingDays);
  const prevAvail = active.length * availPerCrane;
  const prevBooked = _bookedHoursByMachine(prevStart, prevEnd).total;
  const prevPct = prevAvail > 0 ? Math.round(prevBooked / prevAvail * 100) : 0;

  return {
    pct, totalBooked, totalAvail, workingDays,
    activeCount: active.length, totalCount: cranes.length,
    byType, byUnit, diff: pct - prevPct,
  };
}

function UtilizationCard({ info, onOpen }) {
  const diff = info.diff;
  const Trend = diff >= 0 ? TrendUp : TrendDown;
  return (
    <button type="button" className="stat-card stat-card--action" onClick={onOpen}>
      <div className="stat-card__head">
        <div className="stat-card__icon stat-card__icon--blue"><Activity size={20}/></div>
        <div className={"stat-card__delta stat-card__delta--" + (diff >= 0 ? 'up' : 'down')}>
          <Trend size={12}/>{diff >= 0 ? '+' : '−'}{Math.abs(diff)} pts vs last month
        </div>
      </div>
      <div className="stat-card__label">Crane Utilization</div>
      <div className="stat-card__value">{info.pct}%</div>
      <div style={{fontSize: 13, color: 'var(--color-grey-600)', display: 'flex', alignItems: 'baseline', gap: 6, flexWrap: 'wrap'}}>
        <span style={{fontWeight: 700, color: 'var(--color-navy)'}}>{info.activeCount} of {info.totalCount}</span>
        <span style={{color: 'var(--color-grey-500)'}}>cranes active</span>
      </div>
      <span className="stat-card__more">Breakdown <ChevRight size={12}/></span>
    </button>
  );
}

function _UtilRow({ label, sub, pct }) {
  const tone = pct >= 75 ? 'var(--color-green, #1f9d55)' : pct >= 45 ? 'var(--color-yellow-700)' : 'var(--color-navy)';
  return (
    <div style={{display: 'flex', alignItems: 'center', gap: 12}}>
      <div style={{flex: 1, minWidth: 0}}>
        <div style={{display: 'flex', justifyContent: 'space-between', gap: 10}}>
          <span style={{fontWeight: 700, color: 'var(--color-navy)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis'}}>{label}</span>
          <span style={{fontWeight: 700, color: 'var(--color-navy)', whiteSpace: 'nowrap'}}>{pct}%</span>
        </div>
        <div style={{height: 6, borderRadius: 3, background: 'var(--color-grey-100)', marginTop: 6, overflow: 'hidden'}}>
          <div style={{height: '100%', width: Math.min(100, pct) + '%', background: tone, borderRadius: 3}}/>
        </div>
        {sub ? <div style={{fontSize: 12, color: 'var(--color-grey-500)', marginTop: 4}}>{sub}</div> : null}
      </div>
    </div>
  );
}

function UtilizationModal({ info, monthLabel, onClose }) {
  const fmtH = (n) => Math.round(n).toLocaleString('en-MY') + 'h';
  return (
    <div className="install-modal" onClick={onClose}>
      <div className="install-modal__card" onClick={e => e.stopPropagation()} style={{maxWidth: 560, width: '94vw', maxHeight: '88vh', overflowY: 'auto'}}>
        <div style={{display: 'flex', alignItems: 'center', gap: 12, marginBottom: 16}}>
          <div style={{width: 44, height: 44, borderRadius: 10, background: 'var(--color-navy)', display: 'grid', placeItems: 'center', color: 'var(--color-yellow)', flexShrink: 0}}>
            <Activity size={20}/>
          </div>
          <div style={{flex: 1, minWidth: 0}}>
            <div style={{fontWeight: 700, fontSize: 17, color: 'var(--color-navy)'}}>Crane Utilization · {monthLabel}</div>
            <div style={{fontSize: 12, color: 'var(--color-grey-500)', marginTop: 2}}>Booked ÷ available hours, month-to-date · Mon–Sat, {HOURS_PER_DAY}h/day</div>
          </div>
          <button type="button" className="install-banner__close" onClick={onClose}><X size={18}/></button>
        </div>

        <div style={{background: 'var(--color-grey-50, #f6f7f9)', borderRadius: 12, padding: '14px 16px', marginBottom: 20, display: 'flex', gap: 18, flexWrap: 'wrap'}}>
          <div>
            <div style={{fontSize: 26, fontWeight: 800, color: 'var(--color-navy)', lineHeight: 1}}>{info.pct}%</div>
            <div style={{fontSize: 12, color: 'var(--color-grey-500)', marginTop: 4}}>Fleet utilization</div>
          </div>
          <div style={{borderLeft: '1px solid var(--color-grey-200, #e3e6ea)', paddingLeft: 18}}>
            <div style={{fontSize: 14, fontWeight: 700, color: 'var(--color-navy)'}}>{fmtH(info.totalBooked)} / {fmtH(info.totalAvail)}</div>
            <div style={{fontSize: 12, color: 'var(--color-grey-500)', marginTop: 4}}>{info.activeCount} active cranes · {info.workingDays} working day{info.workingDays === 1 ? '' : 's'} so far</div>
          </div>
        </div>

        <div style={{fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '.04em', color: 'var(--color-grey-500)', marginBottom: 12}}>By machine type</div>
        <div style={{display: 'flex', flexDirection: 'column', gap: 14, marginBottom: 24}}>
          {info.byType.map(t => (
            <_UtilRow key={t.category} label={t.category} pct={t.pct} sub={`${t.count} unit${t.count === 1 ? '' : 's'} · ${fmtH(t.booked)} booked`}/>
          ))}
        </div>

        <div style={{fontSize: 12, fontWeight: 700, textTransform: 'uppercase', letterSpacing: '.04em', color: 'var(--color-grey-500)', marginBottom: 12}}>By unit · busiest first</div>
        <div style={{display: 'flex', flexDirection: 'column', gap: 14}}>
          {info.byUnit.map(u => (
            <_UtilRow key={u.machine.id} label={machineLabel(u.machine)} pct={u.pct} sub={`${u.machine.category} · ${fmtH(u.booked)} booked`}/>
          ))}
        </div>
      </div>
    </div>
  );
}

function Dashboard({ setPage }) {
  const [showEarners, setShowEarners] = React.useState(false);
  const [showUtil, setShowUtil] = React.useState(false);
  const earnerInfo = React.useMemo(computeHighestEarner, []);
  const jobsMonth = React.useMemo(computeJobsThisMonth, []);
  const topType = React.useMemo(computeTopCraneType, []);
  const revenue = React.useMemo(computeMonthlyRevenue, []);
  const util = React.useMemo(computeUtilization, []);
  const _monthLabel = new Date(TODAY + 'T12:00:00').toLocaleDateString('en-GB', { month: 'short' });
  const jobsMonthDelta = jobsMonth.deltaPct !== null
    ? (jobsMonth.deltaPct >= 0 ? '+' : '−') + Math.abs(jobsMonth.deltaPct) + '% vs last month'
    : null;
  const revenueDelta = revenue.deltaPct !== null
    ? (revenue.deltaPct >= 0 ? '+' : '−') + Math.abs(revenue.deltaPct) + '% vs last month'
    : null;
  // ===== Today's Jobs =====================================================
  // Shown as fleet utilisation %: booked crane-days today ÷ operable cranes.
  // Each booking contributes hours/8 of a crane-day (8h = a full day's job).
  // Cancelled bookings don't count. Trend = today's % − yesterday's %, in pts.
  const NON_BOOKED = new Set(['Cancelled']);
  const hoursOf = (b) => {
    if (!b.start || !b.end) return 0;
    const [sh, sm] = b.start.split(':').map(Number);
    const [eh, em] = b.end.split(':').map(Number);
    return Math.max(0, (eh + (em || 0) / 60) - (sh + (sm || 0) / 60));
  };
  const jobUnitsOn = (dateISO) =>
    BOOKINGS
      .filter(b => b.date === dateISO && !NON_BOOKED.has(b.status))
      .reduce((sum, b) => sum + hoursOf(b) / 8, 0);
  const yesterdayISO = (() => {
    // Use noon + local date parts so the result isn't shifted a day by the
    // UTC conversion in toISOString().
    const d = new Date(TODAY + 'T12:00:00'); d.setDate(d.getDate() - 1);
    const y = d.getFullYear(), m = String(d.getMonth() + 1).padStart(2, '0'), dd = String(d.getDate()).padStart(2, '0');
    return `${y}-${m}-${dd}`;
  })();
  // Daily capacity = number of operable cranes (anything not flagged unavailable).
  const fleetCapacity = Math.max(1, MACHINES.filter(m => m.status !== 'unavailable').length);
  const pctOn = (dateISO) => Math.round((jobUnitsOn(dateISO) / fleetCapacity) * 100);
  const todayPct = pctOn(TODAY);
  const yPct = pctOn(yesterdayISO);
  const jobsDiff = todayPct - yPct;
  const todayJobsValue = todayPct + '%';
  const todayJobsDelta = (jobsDiff >= 0 ? '+' : '−') + Math.abs(jobsDiff) + ' pts vs yesterday';
  const todayJobsDir = jobsDiff >= 0 ? 'up' : 'down';

  return (
    <div className="content">
      <div className="stats-grid">
        <StatCard icon="Briefcase" iconKind="yellow" label="Today's Jobs" value={todayJobsValue} delta={todayJobsDelta} deltaDir={todayJobsDir}/>
        <HighestEarnerCard info={earnerInfo} onOpen={() => setShowEarners(true)}/>
        <StatCard icon="Calendar" iconKind="green" label={"Jobs This Month (" + _monthLabel + ")"} value={String(jobsMonth.cur)} delta={jobsMonthDelta} deltaDir={jobsMonth.deltaDir}/>
        <TopCraneTypeCard info={topType} monthLabel={_monthLabel}/>
        <StatCard icon="DollarSign" iconKind="yellow" label={"Monthly Revenue (" + _monthLabel + ")"} value={_fmtMoneyShort(revenue.cur)} delta={revenueDelta} deltaDir={revenue.deltaDir}/>
        <UtilizationCard info={util} onOpen={() => setShowUtil(true)}/>
      </div>

      <div style={{marginBottom: 24}}>
        <div className="section-title">
          <h2>Quick Actions</h2>
          <span className="section-title__sub">Most-used dispatcher tools</span>
        </div>
        <div className="qa-grid">
          <QABtn primary icon="Plus" title="Create Work Order" sub="New job + assign staff" onClick={() => setPage('create')}/>
          <QABtn icon="Users" title="Assign Staff" sub="Operator & rigger" onClick={() => setPage('workorders')}/>
          <QABtn icon="Download" title="Export AutoCount" sub="CSV / Excel" onClick={() => setPage('export')}/>
          <QABtn icon="BarChart" title="View Analytics" sub="Revenue & utilization" onClick={() => setPage('analytics')}/>
          <QABtn icon="Send" title="Send Notification" sub="Push / WhatsApp" onClick={() => setPage('notifications')}/>
        </div>
      </div>

      <div className="two-col">
        <div className="card">
          <div className="card__header">
            <div className="card__title">Today's Schedule</div>
            <button className="btn btn--ghost" onClick={() => setPage('workorders')} style={{height: 32, fontSize: 13, padding: '0 12px'}}>
              View all <ChevRight size={14}/>
            </button>
          </div>
          <table className="table" style={{margin: '-4px -8px 0', width: 'calc(100% + 16px)'}}>
            <thead><tr><th>WO ID</th><th>Customer</th><th>Crane</th><th>Operator</th><th>Status</th></tr></thead>
            <tbody>
              {WORK_ORDERS.filter(w => w.date === TODAY).map(w => {
                const id = (w.machine || w.crane || '').split(' ')[0];
                const m = MACHINES.find(x => x.id === id);
                const dot = m ? m.status : 'unavailable';
                const ms = dot === 'available'
                  ? { color: 'green', label: 'Available' }
                  : dot === 'occupied'
                  ? { color: 'red', label: 'Booked' }
                  : { color: 'gray', label: 'Not available' };
                return (
                  <tr key={w.id} style={{cursor: 'pointer'}}>
                    <td style={{fontWeight: 600, color: 'var(--color-navy)'}}>{w.id}</td>
                    <td>{w.customer}</td>
                    <td>{m ? machineLabel(m) : w.tonnage}</td>
                    <td>{w.operator}</td>
                    <td><span className={"status status--" + ms.color}>{ms.label}</span></td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>

        <div style={{display: 'flex', flexDirection: 'column', gap: 24}}>
          <div className="card">
            <div className="card__header">
              <div className="card__title">Jobs This Week</div>
            </div>
            <MiniBarChart/>
          </div>

          <div className="card">
            <div className="card__header">
              <div className="card__title">Live Fleet Status</div>
            </div>
            <div style={{display: 'flex', flexDirection: 'column', gap: 12}}>
              {[
                { id: 'PLC-001', loc: 'Pasir Gudang', status: 'active' },
                { id: 'PLC-009', loc: 'Medini', status: 'active' },
                { id: 'PLC-011', loc: 'Yard — Skudai', status: 'idle' },
                { id: 'PLC-015', loc: 'Workshop', status: 'repair' },
              ].map(c => {
                const m = MACHINES.find(x => x.id === c.id);
                const name = m ? machineLabel(m) : c.id;
                return (
                <div key={c.id} style={{display: 'flex', alignItems: 'center', gap: 12}}>
                  <div style={{width: 36, height: 36, borderRadius: 8, background: 'var(--color-grey-100)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--color-navy)'}}>
                    <Crane size={18}/>
                  </div>
                  <div style={{flex: 1, minWidth: 0}}>
                    <div style={{fontSize: 13, fontWeight: 600, color: 'var(--color-navy)'}}>{name}</div>
                    <div style={{fontSize: 12, color: 'var(--color-grey-500)'}}>{c.loc}</div>
                  </div>
                  <span className={"badge badge--" + (c.status === 'active' ? 'green' : c.status === 'idle' ? 'gray' : 'red')}>
                    {c.status === 'active' ? 'On site' : c.status === 'idle' ? 'Idle' : 'Repair'}
                  </span>
                </div>
                );
              })}
            </div>
          </div>
        </div>
      </div>
      {showEarners ? <TopEarnersModal info={earnerInfo} onClose={() => setShowEarners(false)}/> : null}
      {showUtil ? <UtilizationModal info={util} monthLabel={_monthLabel} onClose={() => setShowUtil(false)}/> : null}
    </div>
  );
}

Object.assign(window, { Dashboard });
