/* ============================================================
   App root — state, scheduler wiring, simulation, exports
   ============================================================ */

/* ════════════════════════════════════════════════════════════
   🔑  SET YOUR DASHBOARD PASSWORD HERE
   Change the text between the quotes to whatever you want.
   Anyone opening the dashboard must type this to get in.
   ════════════════════════════════════════════════════════════ */
const ACCESS_PASSWORD = 'ejay2026';

const DEFAULT_WEEK = '2026-06-15'; // Monday

function defaultTrucks() {
  return [
    { id: 'T1', name: 'Truck 1 — Cascadia', code: 'T-01', plate: 'NC 8842-RF' },
    { id: 'T2', name: 'Truck 2 — Volvo VNL', code: 'T-02', plate: 'NC 5519-KM' },
    { id: 'T3', name: 'Truck 3 — Kenworth', code: 'T-03', plate: 'NC 7203-PB' },
  ];
}
function defaultDrivers() {
  return [
    { id: 1, name: 'Marcus Bell',     phone: '(704) 555-0142', license: 'CDL-A', status: 'Active', assignedTruck: 'T1' },
    { id: 2, name: 'Luis Romero',     phone: '(919) 555-0188', license: 'CDL-A', status: 'Active', assignedTruck: 'T2' },
    { id: 3, name: 'Andre Whitfield', phone: '(336) 555-0173', license: 'CDL-A', status: 'Active', assignedTruck: 'T3' },
    { id: 4, name: 'Devon Clarke',    phone: '(704) 555-0119', license: 'CDL-A', status: 'Active', assignedTruck: 'T1' },
    { id: 5, name: 'Ray Sandoval',    phone: '(910) 555-0156', license: 'CDL-A', status: 'Active', assignedTruck: 'T2' },
    { id: 6, name: 'Tyler Hodge',     phone: '(828) 555-0134', license: 'CDL-A', status: 'Active', assignedTruck: 'T3' },
  ];
}

function App() {
  const [authed, setAuthed] = useState(() => {
    try { return sessionStorage.getItem('ejay_auth') === '1'; } catch (_) { return false; }
  });
  const [password, setPassword] = useState(() => {
    try { return localStorage.getItem('ejay_pw') || ACCESS_PASSWORD; } catch (_) { return ACCESS_PASSWORD; }
  });
  const [view, setView] = useState('dashboard');
  const [theme, setTheme] = useState('dark');
  const [weekStart, setWeekStartRaw] = useState(DEFAULT_WEEK);
  const [drivers, setDrivers] = useState(defaultDrivers());
  const [trucks, setTrucks] = useState(defaultTrucks());
  const [schedule, setSchedule] = useState(() => Engine.generate(DEFAULT_WEEK, defaultDrivers(), defaultTrucks()));
  const [simulating, setSimulating] = useState(false);
  const [simDate, setSimDate] = useState(DEFAULT_WEEK);
  const [toast, setToast] = useState(null);
  const [mobileOpen, setMobileOpen] = useState(false);
  const [dispatcherDone, setDispatcherDone] = useState(() => {
    try { return JSON.parse(localStorage.getItem('ejay_dispatcher_v1') || '{}'); } catch (e) { return {}; }
  });
  const toastTimer = useRef(null);

  useEffect(() => {
    try { localStorage.setItem('ejay_dispatcher_v1', JSON.stringify(dispatcherDone)); } catch (e) {}
  }, [dispatcherDone]);

  useEffect(() => { document.documentElement.setAttribute('data-theme', theme); }, [theme]);

  const flash = (msg) => {
    setToast(msg);
    clearTimeout(toastTimer.current);
    toastTimer.current = setTimeout(() => setToast(null), 2200);
  };

  const regenerate = (ws, drv, trk) => {
    const start = Engine.snapToMonday(ws || weekStart);
    setSchedule(Engine.generate(start, drv || drivers, trk || trucks));
  };

  const setWeekStart = (d) => { setWeekStartRaw(d); };

  const generate = () => {
    setSimulating(false);
    const start = Engine.snapToMonday(weekStart);
    setSchedule(Engine.generate(start, drivers, trucks));
    setSimDate(start);
    flash('Weekly schedule generated');
  };

  const reset = () => {
    setSimulating(false);
    const d = defaultDrivers(), t = defaultTrucks();
    setDrivers(d); setTrucks(t); setWeekStartRaw(DEFAULT_WEEK);
    setSchedule(Engine.generate(DEFAULT_WEEK, d, t));
    setSimDate(DEFAULT_WEEK);
    flash('Reset to default demo');
  };

  /* ---- driver CRUD ---- */
  const addDriver = (form) => {
    const id = drivers.reduce((m, d) => Math.max(m, d.id), 0) + 1;
    const nd = [...drivers, { id, ...form }];
    setDrivers(nd); regenerate(null, nd, null); flash('Driver added');
  };
  const updateDriver = (id, form) => {
    const nd = drivers.map(d => d.id === id ? { ...d, ...form } : d);
    setDrivers(nd); regenerate(null, nd, null); flash('Driver updated');
  };
  const deleteDriver = (id) => {
    const nd = drivers.filter(d => d.id !== id);
    setDrivers(nd); regenerate(null, nd, null); flash('Driver removed');
  };

  /* ---- truck CRUD ---- */
  const addTruck = (form) => {
    const id = 'T' + (trucks.reduce((m, t) => Math.max(m, +String(t.id).replace(/\D/g, '') || 0), 0) + 1);
    const nt = [...trucks, { id, ...form }];
    setTrucks(nt); regenerate(null, null, nt); flash('Truck added');
  };
  const updateTruck = (id, form) => {
    const nt = trucks.map(t => t.id === id ? { ...t, ...form } : t);
    setTrucks(nt); regenerate(null, null, nt); flash('Truck updated');
  };
  const deleteTruck = (id) => {
    const nt = trucks.filter(t => t.id !== id);
    const nd = drivers.map(d => d.assignedTruck === id ? { ...d, assignedTruck: null } : d);
    setTrucks(nt); setDrivers(nd); regenerate(null, nd, nt); flash('Truck removed');
  };

  const autoAssign = () => {
    const nd = Engine.autoAssignTrucks(drivers, trucks);
    setDrivers(nd); regenerate(null, nd, null); flash('Drivers auto-assigned');
  };

  const overrideLeg = (id, patch) => {
    setSchedule(s => s.map(l => l.id === id ? { ...l, ...patch } : l));
    flash('Load status updated');
  };

  /* ---- access password ---- */
  const changePassword = (current, next) => {
    if (current !== password) return 'wrong-current';
    if (!next || next.length < 4) return 'too-short';
    setPassword(next);
    try { localStorage.setItem('ejay_pw', next); } catch (_) {}
    flash('Password updated');
    return 'ok';
  };
  const resetPasswordDefault = () => {
    setPassword(ACCESS_PASSWORD);
    try { localStorage.removeItem('ejay_pw'); } catch (_) {}
    flash('Password reset to default');
  };
  const lockDashboard = () => {
    try { sessionStorage.setItem('ejay_auth', '0'); } catch (_) {}
    setAuthed(false);
  };

  /* ---- simulation ---- */
  const toggleSim = () => {
    if (simulating) { setSimulating(false); return; }
    const dates = Engine.scheduleDates(schedule);
    if (!dates.length) return;
    setSimDate(dates[0]);
    setSchedule(s => Engine.applyClock(s, dates[0]));
    setSimulating(true);
  };

  useEffect(() => {
    if (!simulating) return;
    const dates = Engine.scheduleDates(schedule);
    const id = setInterval(() => {
      setSimDate(prev => {
        let idx = dates.indexOf(prev);
        idx = (idx + 1) % (dates.length + 1);
        const next = idx >= dates.length ? dates[dates.length - 1] : dates[idx];
        const clockDate = idx >= dates.length ? Engine.addDays(dates[dates.length - 1], 1) : dates[idx];
        setSchedule(s => Engine.applyClock(s, clockDate));
        if (idx >= dates.length) { setSimulating(false); return dates[dates.length - 1]; }
        return next;
      });
    }, 1700);
    return () => clearInterval(id);
  }, [simulating]);

  /* ---- exports ---- */
  const buildRows = () => {
    return [...schedule].sort((a, b) => a.date < b.date ? -1 : 1).map(l => {
      const drv = drivers.find(d => d.id === l.driverId) || {};
      const trk = trucks.find(t => t.id === l.truckId) || {};
      const st = l.delayed && l.status !== 'completed' ? 'Delayed' : (STATUS_META[l.status] || {}).label;
      return {
        Date: Engine.fmtFull(l.date),
        Driver: 'Driver ' + l.driverId + ' — ' + (drv.name || ''),
        Truck: trk.code || '',
        Activity: l.leg === 'outbound' ? 'Outbound' : 'Backhaul',
        Route: l.from + ' → ' + l.to,
        Status: st,
      };
    });
  };

  const exportExcel = () => {
    const rows = buildRows();
    const cols = ['Date', 'Driver', 'Truck', 'Activity', 'Route', 'Status'];
    let html = '<table border="1"><thead><tr>' + cols.map(c => '<th>' + c + '</th>').join('') + '</tr></thead><tbody>';
    rows.forEach(r => { html += '<tr>' + cols.map(c => '<td>' + r[c] + '</td>').join('') + '</tr>'; });
    html += '</tbody></table>';
    const blob = new Blob(['\ufeff<html><head><meta charset="utf-8"></head><body>' + html + '</body></html>'],
      { type: 'application/vnd.ms-excel' });
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = 'Ejay-Dispatch-' + weekStart + '.xls';
    a.click();
    flash('Excel exported');
  };

  const exportPdf = () => {
    const rows = buildRows();
    const cols = ['Date', 'Driver', 'Truck', 'Activity', 'Route', 'Status'];
    const w = window.open('', '_blank');
    const body = rows.map(r => '<tr>' + cols.map(c => '<td>' + r[c] + '</td>').join('') + '</tr>').join('');
    w.document.write(`<html><head><title>Ejay Logistics — Weekly Dispatch</title>
      <style>
        body{font-family:Arial,sans-serif;padding:36px;color:#0f1a2c;}
        h1{font-size:20px;margin:0 0 4px;} .sub{color:#64748b;margin:0 0 22px;font-size:13px;}
        table{width:100%;border-collapse:collapse;font-size:12.5px;}
        th{background:#f1f5f9;text-align:left;padding:9px 11px;border-bottom:2px solid #cbd5e1;text-transform:uppercase;font-size:10px;letter-spacing:.06em;}
        td{padding:9px 11px;border-bottom:1px solid #e2e8f0;}
        tr:nth-child(even) td{background:#f8fafc;}
      </style></head><body>
      <h1>Ejay Logistics — Weekly Dispatch</h1>
      <p class="sub">Week of ${Engine.fmtFull(Engine.snapToMonday(weekStart))} · ${rows.length} legs · NC ⇄ NJ</p>
      <table><thead><tr>${cols.map(c => '<th>' + c + '</th>').join('')}</tr></thead><tbody>${body}</tbody></table>
      </body></html>`);
    w.document.close();
    setTimeout(() => w.print(), 350);
    flash('PDF ready — use Save as PDF');
  };

  const ctx = {
    drivers, trucks, schedule, weekStart, theme, simulating, simDate,
    setView, setWeekStart, setTheme, generate, reset, autoAssign,
    addDriver, updateDriver, deleteDriver,
    addTruck, updateTruck, deleteTruck,
    overrideLeg, exportExcel, exportPdf,
    dispatcherDone, setDispatcherDone,
    changePassword, resetPasswordDefault, lockDashboard, defaultPassword: ACCESS_PASSWORD,
  };

  // "today" follows the live-sim clock while running, else NC (US Eastern) date
  const todayStr = simulating ? simDate : Engine.todayET();
  const dispMonday = Engine.snapToMonday(weekStart);
  let dispatcherAlerts = 0;
  (window.DISPATCH_WEEK || []).forEach((d, di) => {
    const dayDate = Engine.addDays(dispMonday, di);
    if (dayDate < todayStr) {
      d.tasks.forEach((t, ti) => { if (!dispatcherDone[di + '-' + ti]) dispatcherAlerts++; });
    }
  });

  const counts = { drivers: drivers.length, trucks: trucks.length, dispatcherAlerts: dispatcherAlerts };

  if (!authed) {
    return <LoginGate expected={password} onSuccess={() => setAuthed(true)} />;
  }

  let CurrentView;
  if (view === 'dashboard') CurrentView = <DashboardView ctx={ctx} />;
  else if (view === 'drivers') CurrentView = <DriversView ctx={ctx} />;
  else if (view === 'trucks') CurrentView = <TrucksView ctx={ctx} />;
  else if (view === 'schedule') CurrentView = <ScheduleView ctx={ctx} />;
  else if (view === 'board') CurrentView = <BoardView ctx={ctx} />;
  else if (view === 'dispatcher') CurrentView = <DispatcherView ctx={ctx} />;
  else CurrentView = <SettingsView ctx={ctx} />;

  return (
    <div className="app">
      {mobileOpen && <div className="scrim" onClick={() => setMobileOpen(false)}></div>}
      <Sidebar view={view} setView={setView} counts={counts} simulating={simulating}
               toggleSim={toggleSim} mobileOpen={mobileOpen} closeMobile={() => setMobileOpen(false)} />
      <div className="main">
        <Topbar view={view} weekStart={weekStart} theme={theme}
                toggleTheme={() => setTheme(t => t === 'dark' ? 'light' : 'dark')}
                simulating={simulating} simDate={simDate} onMenu={() => setMobileOpen(true)} />
        <div className="content">{CurrentView}</div>
      </div>
      <Toast msg={toast} />
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);

// Fade out the preloader once the app has mounted and painted.
requestAnimationFrame(() => setTimeout(() => {
  const pl = document.getElementById('ejay-preloader');
  if (pl) { pl.classList.add('hide'); setTimeout(() => { pl.style.display = 'none'; }, 500); }
}, 300));
