// United King Sales Forecast & Requisitions — top-level shell.
// Two views: a product list (Page 1) and per-product detail (Page 2).
//
// Branch is a single-select on Page 1, inherited by Page 2. State for which
// products had a requisition submitted today is persisted in localStorage
// (see data-loader.js) — that's what the "Requisition sent" badges read.

const App = () => {
  const M = window.__DATA || {};
  // Defensive defaults so a slim/unexpected bootstrap shape doesn't blow up render.
  M.products    = M.products    || [];
  M.branches    = M.branches    || [];
  M.festivals   = M.festivals   || [];
  M.festivalCols = M.festivalCols || [];
  const run_date = M.run_date;

  // ---- Tweaks (defaults) ----
  const tweakDefaults = /*EDITMODE-BEGIN*/{
    "scenario": "normal"
  }/*EDITMODE-END*/;
  const [tweaks, setTweak] = window.useTweaks(tweakDefaults);

  // ---- View routing ----
  const [view, setView] = React.useState('list'); // 'list' | 'detail'
  const [selectedProduct, setSelectedProduct] = React.useState(null);

  // ---- Branch (single, persisted) ----
  const BRANCH_KEY = 'uk-branch';
  const initialBranch = (() => {
    const saved = localStorage.getItem(BRANCH_KEY);
    if (saved && M.branches.some(b => b.name === saved)) return saved;
    return M.branches[0]?.name || '';
  })();
  const [branch, setBranchState] = React.useState(initialBranch);
  const setBranch = (b) => {
    setBranchState(b);
    localStorage.setItem(BRANCH_KEY, b);
  };

  // ---- "Ordered today" set + pending-quantity map. Both keyed by (run_date, branch).
  // Increment a version counter to force re-reads from localStorage after any
  // change (set/remove/submit) — pendingMap is reads-from-storage rather than
  // primary state so Page 1 and Page 2 stay in lockstep without prop drilling. ----
  const [stateVersion, setStateVersion] = React.useState(0);
  const bumpState = React.useCallback(() => setStateVersion(v => v + 1), []);

  const orderedToday = React.useMemo(
    () => window.getOrderedProductsToday({ run_date, branch }),
    [run_date, branch, stateVersion]
  );
  const pendingMap = React.useMemo(
    () => window.getPendingForBranch({ run_date, branch }),
    [run_date, branch, stateVersion]
  );

  // ---- Modal + toast ----
  const [modalState, setModalState] = React.useState({ open: false, rows: [], title: '' });
  const [toast, setToast] = React.useState({ open: false, type: 'success', message: '' });
  const [changePwdOpen, setChangePwdOpen] = React.useState(false);

  // ---- Freshness polling. Detects new pipeline runs after page load so the
  // user gets a banner instead of having to F5. Polls /api/freshness every
  // 5 minutes (just a MAX(run_date) — cheap). Banner stays until refresh
  // or explicit dismiss. ----
  const [freshAvailable, setFreshAvailable] = React.useState(false);
  React.useEffect(() => {
    const initialLastRun = M.last_run;
    if (!initialLastRun) return; // no baseline → skip polling
    let cancelled = false;
    const check = async () => {
      try {
        const res = await window.authFetch('/api/freshness');
        if (!res.ok || cancelled) return;
        const data = await res.json();
        if (data.last_run && data.last_run !== initialLastRun) {
          setFreshAvailable(true);
        }
      } catch (_) { /* transient network errors are fine */ }
    };
    const id = setInterval(check, 5 * 60 * 1000); // every 5 min
    return () => { cancelled = true; clearInterval(id); };
  }, [M.last_run]);

  // Build the list of pending rows (one per pending product) and open the
  // existing requisition modal as a final review step before POSTing /api/orders.
  const handleOpenSubmitAll = () => {
    const rows = Object.entries(pendingMap)
      .filter(([, q]) => q > 0)
      .map(([prodName, q]) => {
        const meta = M.products.find(p => p.name === prodName);
        const branchMeta = M.branches.find(b => b.name === branch);
        if (!meta || !branchMeta) return null;
        return {
          product: prodName,
          branch,
          product_id: meta.id,
          branch_id: branchMeta.id,
          predicted: 0,
          inventory: 0,
          order_qty_predicted: q,
          minimumOrderQuantity: meta.master?.minimumOrderQuantity || null,
        };
      })
      .filter(Boolean);
    if (rows.length === 0) return;
    setModalState({ open: true, rows, title: `Submit Requisition · ${branch}` });
  };

  const handleSubmitOrder = (payload) => {
    setModalState(s => ({ ...s, open: false }));
    const products = payload.map(p => {
      const meta = M.products.find(mp => mp.id === p.product_id);
      return meta?.name;
    }).filter(Boolean);
    if (products.length) {
      window.markOrderSubmitted({ run_date, branch, products });
      window.clearPendingProducts({ run_date, branch, products });
      bumpState();
    }
    setToast({
      open: true,
      type: 'success',
      message: `Submitted: ${payload.length} item${payload.length === 1 ? '' : 's'}, ${payload.reduce((s, r) => s + r.quantity, 0).toLocaleString()} units`,
    });
  };

  // ---- Upcoming festivals (from run_date onward, used by detail view side panel + KPIs) ----
  const upcomingFestivals = React.useMemo(() => {
    return M.festivals
      .filter(f => f.is_festival_day === 1 && f.date >= run_date)
      .map(f => {
        const name = M.festivalCols.find(c => f[c] === 1) || 'Festival';
        return { date: f.date, name };
      })
      .sort((a, b) => a.date.localeCompare(b.date));
  }, [run_date]);

  // ---- Header KPIs (Last Run + Next Festival, shown on both views) ----
  const nextFestival = React.useMemo(() => {
    const upcoming = upcomingFestivals[0];
    if (!upcoming) return null;
    const days = Math.round((new Date(upcoming.date) - new Date(run_date)) / 86400000);
    return { name: upcoming.name.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()), days, date: upcoming.date };
  }, [upcomingFestivals, run_date]);
  const lastRunDate = M.last_run;

  return (
    <div className="min-h-screen bg-slate-50 text-slate-900">
      {/* TOP BAR */}
      <header className="sticky top-0 z-40 bg-red-600 text-white shadow-sm">
        <div className="max-w-[1600px] mx-auto px-4 sm:px-6 h-16 flex items-center justify-between gap-4">
          <div className="flex items-center gap-3 min-w-0">
            <div className="bg-white rounded px-1.5 py-0.5 shrink-0">
              <img src="assets/united-king-logo.png" alt="United King" className="h-9 w-auto block" />
            </div>
            <div className="hidden sm:block min-w-0">
              <h1 className="text-base font-semibold leading-tight truncate">Sales Forecast & Requisitions</h1>
              <p className="text-[11px] text-red-100 leading-tight">
                {view === 'list' ? 'Representative Dashboard' : `${selectedProduct?.name} · ${branch}`}
              </p>
            </div>
          </div>
          <div className="flex items-center gap-2 sm:gap-3">
            {nextFestival && (
              <KpiChip
                icon={<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 4.5L7 1l5 3.5v6L7 13 2 10.5v-6z" stroke="currentColor" strokeWidth="1.3" strokeLinejoin="round"/></svg>}
                label="Next Festival"
                primary={`${nextFestival.days}d`}
                sub={nextFestival.name}
              />
            )}
            <KpiChip
              icon={<svg width="14" height="14" viewBox="0 0 14 14" fill="none"><circle cx="7" cy="7" r="5.5" stroke="currentColor" strokeWidth="1.3"/><path d="M7 4v3l2 1.5" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round"/></svg>}
              label="Last Run"
              primary={lastRunDate ? new Date(lastRunDate).toLocaleDateString('en-US', { month: 'short', day: 'numeric' }) : '—'}
              sub="07:30 PKT"
            />
            <UserMenu onChangePassword={() => setChangePwdOpen(true)} />
          </div>
        </div>
      </header>

      {/* FRESHNESS BANNER — surfaces "new pipeline run available" without
          forcing a reload. Sticky so it's visible after scrolling Page 1/2. */}
      {freshAvailable && (
        <FreshnessBanner
          onRefresh={() => window.location.reload()}
          onDismiss={() => setFreshAvailable(false)}
        />
      )}

      {/* VIEW */}
      {view === 'list' ? (
        <ProductListView
          M={M}
          selectedBranch={branch}
          onSelectBranch={setBranch}
          orderedToday={orderedToday}
          pendingMap={pendingMap}
          onPendingChange={bumpState}
          onOpenProduct={(p) => { setSelectedProduct(p); setView('detail'); }}
          onSubmitAll={handleOpenSubmitAll}
        />
      ) : (
        <ProductDetailView
          M={M}
          product={selectedProduct}
          branch={branch}
          onBack={() => setView('list')}
          orderedToday={orderedToday}
          pendingMap={pendingMap}
          onPendingChange={bumpState}
          upcomingFestivals={upcomingFestivals}
          tweaks={tweaks}
          onTweakChange={setTweak}
        />
      )}

      {/* MODAL */}
      <RequisitionModal
        open={modalState.open}
        title={modalState.title}
        rows={modalState.rows}
        onClose={() => setModalState(s => ({ ...s, open: false }))}
        onSubmit={handleSubmitOrder}
      />

      {/* CHANGE PASSWORD MODAL */}
      <ChangePasswordModal
        open={changePwdOpen}
        onClose={() => setChangePwdOpen(false)}
        onSuccess={() => setToast({ open: true, type: 'success', message: 'Password updated.' })}
      />

      {/* TOAST */}
      <Toast
        open={toast.open}
        type={toast.type}
        message={toast.message}
        onClose={() => setToast(t => ({ ...t, open: false }))}
      />

      {/* TWEAKS — only meaningful on detail view (scenario multipliers) */}
      {view === 'detail' && (
        <TweaksPanel title="Tweaks">
          <TweakSection label="Data scenario">
            <TweakRadio
              label="Scenario"
              value={tweaks.scenario}
              options={[
                { value: 'normal', label: 'Normal' },
                { value: 'spike', label: 'Festival spike' },
                { value: 'low', label: 'Low inventory' },
              ]}
              onChange={(v) => setTweak('scenario', v)}
            />
          </TweakSection>
        </TweaksPanel>
      )}
    </div>
  );
};

// Avatar + dropdown in the header. Reads email/name from localStorage (set by
// /login.html on successful sign-in). Closes on outside click or Escape.
const UserMenu = ({ onChangePassword }) => {
  const [open, setOpen] = React.useState(false);
  const wrapRef = React.useRef(null);

  const email = (typeof localStorage !== 'undefined' && localStorage.getItem('uk-auth-email')) || '';
  const name  = (typeof localStorage !== 'undefined' && localStorage.getItem('uk-auth-name'))  || '';
  const initial = ((name || email || '?').trim().charAt(0) || '?').toUpperCase();

  React.useEffect(() => {
    if (!open) return;
    const onDocClick = (e) => {
      if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
    };
    const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
    document.addEventListener('mousedown', onDocClick);
    document.addEventListener('keydown', onKey);
    return () => {
      document.removeEventListener('mousedown', onDocClick);
      document.removeEventListener('keydown', onKey);
    };
  }, [open]);

  return (
    <div className="relative" ref={wrapRef}>
      <button
        onClick={() => setOpen(o => !o)}
        title={email || 'Account'}
        aria-label="Account menu"
        className="w-9 h-9 rounded-full bg-white/15 hover:bg-white/25 border border-white/15 text-white text-sm font-semibold flex items-center justify-center transition"
      >
        {initial}
      </button>

      {open && (
        <div className="absolute right-0 mt-2 w-60 bg-white text-slate-900 rounded-md shadow-lg border border-slate-200 overflow-hidden z-50">
          <div className="px-3 py-2.5 border-b border-slate-100">
            <div className="text-sm font-medium truncate">{name || 'Signed in'}</div>
            <div className="text-xs text-slate-500 truncate">{email || '—'}</div>
          </div>
          <button
            onClick={() => { setOpen(false); onChangePassword && onChangePassword(); }}
            className="w-full text-left px-3 py-2 text-sm hover:bg-slate-50 flex items-center gap-2"
          >
            <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
              <rect x="2.5" y="6" width="9" height="6" rx="1" stroke="currentColor" strokeWidth="1.3"/>
              <path d="M4.5 6V4.5a2.5 2.5 0 015 0V6" stroke="currentColor" strokeWidth="1.3"/>
            </svg>
            Change password
          </button>
          <button
            onClick={() => { setOpen(false); window.logout && window.logout(); }}
            className="w-full text-left px-3 py-2 text-sm text-red-700 hover:bg-red-50 flex items-center gap-2 border-t border-slate-100"
          >
            <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
              <path d="M6 12H3a1 1 0 01-1-1V3a1 1 0 011-1h3" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round"/>
              <path d="M9 4l3 3-3 3M12 7H6" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/>
            </svg>
            Sign out
          </button>
        </div>
      )}
    </div>
  );
};

const FreshnessBanner = ({ onRefresh, onDismiss }) => (
  <div className="sticky top-16 z-30 bg-amber-50 border-b border-amber-200">
    <div className="max-w-[1600px] mx-auto px-4 sm:px-6 py-2 flex items-center justify-center gap-3 text-xs">
      <svg width="14" height="14" viewBox="0 0 14 14" fill="none" className="text-amber-700 shrink-0">
        <path d="M7 1.5v5l3 1.5" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/>
        <circle cx="7" cy="7" r="5.5" stroke="currentColor" strokeWidth="1.3"/>
      </svg>
      <span className="text-amber-900 font-medium">New forecast data available.</span>
      <button
        onClick={onRefresh}
        className="font-semibold text-amber-900 hover:underline underline-offset-2"
      >
        Refresh
      </button>
      <button
        onClick={onDismiss}
        title="Dismiss"
        className="ml-1 text-amber-600 hover:text-amber-900 text-base leading-none -mt-0.5"
      >
        ×
      </button>
    </div>
  </div>
);

const KpiChip = ({ icon, label, primary, sub }) => (
  <div className="bg-white/15 backdrop-blur-sm rounded-md px-2.5 py-1 flex items-center gap-2 border border-white/15">
    <div className="text-red-100 hidden sm:block">{icon}</div>
    <div className="leading-tight">
      <div className="text-[9px] uppercase tracking-wide text-red-100 font-medium">{label}</div>
      <div className="text-xs font-semibold whitespace-nowrap">
        {primary}
        <span className="text-red-100 font-normal ml-1 hidden md:inline">· {sub}</span>
      </div>
    </div>
  </div>
);

// Catch render-time crashes so we see the error in the page instead of a white screen.
class ErrorBoundary extends React.Component {
  constructor(props) { super(props); this.state = { err: null }; }
  static getDerivedStateFromError(err) { return { err }; }
  componentDidCatch(err, info) { console.error('App crashed:', err, info); }
  render() {
    if (this.state.err) {
      const e = this.state.err;
      return (
        <div className="min-h-screen flex flex-col items-center justify-center gap-3 text-sm px-6 text-center">
          <strong className="text-red-700 text-base">App crashed</strong>
          <pre className="text-xs text-slate-700 bg-slate-100 p-3 rounded max-w-3xl overflow-auto whitespace-pre-wrap text-left">
            {(e && e.message) || String(e)}{'\n\n'}{(e && e.stack) || ''}
          </pre>
        </div>
      );
    }
    return this.props.children;
  }
}

window.bootstrapData()
  .then(() => ReactDOM.createRoot(document.getElementById('root')).render(
    <ErrorBoundary><App /></ErrorBoundary>
  ))
  .catch(err => {
    document.getElementById('root').innerHTML =
      `<div class="min-h-screen flex flex-col items-center justify-center gap-2 text-red-600 text-sm px-6 text-center">
         <strong>Failed to load data</strong>
         <span class="text-slate-600">${(err && err.message) || err}</span>
       </div>`;
  });
