/* ===== Big Rig — app shell, state, routing ===== */
const { useState: uS, useEffect: uE } = React;

const VARIANT = (new URLSearchParams(location.search)).get('v') || 'app';
const LSKEY = 'bigrig_proto_' + VARIANT;

function loadState() {
  try {
    const raw = JSON.parse(localStorage.getItem(LSKEY) || '{}');
    if (raw.period) raw.period = { start: new Date(raw.period.start), end: new Date(raw.period.end), days: raw.period.days };
    if (raw.cart) raw.cart = raw.cart.filter(l => BR.byId(l.id)).map(l => l.period ? { ...l, period: { start: new Date(l.period.start), end: new Date(l.period.end), days: l.period.days } } : l);
    return raw;
  } catch (e) { return {}; }
}

function App() {
  const init = loadState();
  const [route, setRoute] = uS(init.route || 'home');
  const [productId, setProductId] = uS(BR.byId(init.productId) ? init.productId : 'bigpad');
  const [cat, setCat] = uS(init.cat || 'all');
  const [prodMode, setProdMode] = uS(init.prodMode || 'rent');
  const [period, setPeriod] = uS(init.period || null);
  const [calMonth, setCalMonth] = uS(new Date(2026, 5, 1));
  const [selStart, setSelStart] = uS(null);
  const [selEnd, setSelEnd] = uS(null);
  const [draft, setDraft] = uS({});
  const [cart, setCart] = uS(init.cart || []);
  const [toast, setToast] = uS(null);
  const [orderNo, setOrderNo] = uS(init.orderNo || 0);

  // persist
  uE(() => {
    const ser = {
      route, productId, cat, prodMode, orderNo,
      period: period ? { start: +period.start, end: +period.end, days: period.days } : null,
      cart: cart.map(l => l.period ? { ...l, period: { start: +l.period.start, end: +l.period.end, days: l.period.days } } : l)
    };
    localStorage.setItem(LSKEY, JSON.stringify(ser));
  }, [route, productId, cat, prodMode, period, cart, orderNo]);

  // scroll to top of the app on route change
  uE(() => { const r = document.getElementById('root'); if (r) r.scrollTop = 0; window.scrollTo(0, 0); }, [route]);

  let toastTimer = null;
  const showToast = (msg) => { setToast(msg); clearTimeout(toastTimer); toastTimer = setTimeout(() => setToast(null), 1900); };
  const go = (r) => setRoute(r);

  // ---- stock math ----
  const PADS = ['bigpad', 'smallpad'];
  const reserved = (id) => cart.filter(l => l.kind === 'rent' && l.id === id).reduce((s, l) => s + l.qty, 0);
  const bookCap = (id) => Math.max(0, BR.byId(id).stock - reserved(id));
  const samePeriod = (l, per) => per && +l.period.start === +per.start && +l.period.end === +per.end;
  const padsInPeriodArr = (arr, per) => arr.filter(l => l.kind === 'rent' && PADS.indexOf(l.id) > -1 && samePeriod(l, per)).reduce((s, l) => s + l.qty, 0);
  const padsInCartForPeriod = (per) => padsInPeriodArr(cart, per);
  const calzoneInCartForPeriod = (per) => cart.filter(l => l.kind === 'rent' && l.id === 'calzone' && samePeriod(l, per)).reduce((s, l) => s + l.qty, 0);
  // toppers can only attach to pads in the same booking (draft + already-in-cart for the period)
  const padsInBooking = () => (draft.bigpad || 0) + (draft.smallpad || 0) + padsInCartForPeriod(period);
  const calzoneCap = () => Math.max(0, Math.min(bookCap('calzone'), padsInBooking() - calzoneInCartForPeriod(period)));
  const bookMax = (id) => id === 'calzone' ? calzoneCap() : bookCap(id);
  const availFor = (id) => id === 'calzone' ? Math.max(0, calzoneCap() - (draft.calzone || 0)) : Math.max(0, bookCap(id) - (draft[id] || 0));
  const canAddCalzone = () => padsInCartForPeriod(period) - calzoneInCartForPeriod(period) > 0;

  // ---- product ----
  const openProduct = (id) => { const p = BR.byId(id); setProductId(id); setProdMode(p.rentable ? 'rent' : 'buy'); go('product'); };

  // ---- cart mutations ----
  const addRent = (id, qty) => {
    if (!period || qty <= 0) return;
    const p = BR.byId(id);
    let cap = bookCap(id);
    if (p.rentModel === 'addon') {
      cap = Math.min(cap, padsInCartForPeriod(period) - calzoneInCartForPeriod(period));
      if (cap <= 0) { showToast('Add a pad to your booking first'); return; }
    }
    const add = Math.min(qty, cap);
    if (add <= 0) { showToast('No more ' + p.name + ' for those dates'); return; }
    const unit = BR.rentUnit(p, period.days);
    setCart(prev => {
      const idx = prev.findIndex(l => l.kind === 'rent' && l.id === id && samePeriod(l, period));
      if (idx >= 0) { const c = prev.slice(); c[idx] = { ...c[idx], qty: c[idx].qty + add }; return c; }
      return prev.concat([{ key: 'r' + id + Date.now() + Math.random().toString(36).slice(2, 6), id, kind: 'rent', qty: add, unit, days: period.days, period }]);
    });
    showToast(add + '× ' + p.name + ' added to booking');
  };
  const addBuy = (id, qty) => {
    if (qty <= 0) return;
    const p = BR.byId(id); const unit = p.buy;
    setCart(prev => {
      const idx = prev.findIndex(l => l.kind === 'buy' && l.id === id);
      if (idx >= 0) { const c = prev.slice(); c[idx] = { ...c[idx], qty: c[idx].qty + qty }; return c; }
      return prev.concat([{ key: 'b' + id + Date.now() + Math.random().toString(36).slice(2, 6), id, kind: 'buy', qty, unit }]);
    });
    showToast(qty + '× ' + p.name + ' added to cart');
  };
  const setLineQty = (key, qty) => setCart(prev => prev.map(l => {
    if (l.key !== key) return l;
    let max = 99;
    if (l.kind === 'rent') max = l.id === 'calzone' ? Math.min(BR.byId('calzone').stock, padsInPeriodArr(prev, l.period)) : BR.byId(l.id).stock;
    return { ...l, qty: Math.max(1, Math.min(qty, max)) };
  }));
  const removeLine = (key) => setCart(prev => prev.filter(l => l.key !== key));

  // ---- bulk pad-rental discount ----
  const RENTPADS = ['bigpad', 'smallpad'];
  const padRentQtyIn = (arr) => arr.filter(l => l.kind === 'rent' && RENTPADS.indexOf(l.id) > -1).reduce((s, l) => s + l.qty, 0);
  const padRentSubIn = (arr) => arr.filter(l => l.kind === 'rent' && RENTPADS.indexOf(l.id) > -1).reduce((s, l) => s + l.unit * l.qty, 0);
  const bulkRate = () => BR.padBulkRate(padRentQtyIn(cart));
  const bulkDiscount = () => Math.round(padRentSubIn(cart) * bulkRate());
  const cartTotal = () => cart.reduce((s, l) => s + l.unit * l.qty, 0) - bulkDiscount();
  const cartCount = cart.reduce((s, l) => s + l.qty, 0);

  // ---- booking date selection ----
  const pick = (d) => {
    if (!selStart || (selStart && selEnd)) { setSelStart(d); setSelEnd(null); }
    else if (d > selStart) { setSelEnd(d); }
    else { setSelStart(d); setSelEnd(null); }
  };
  const draftPeriod = () => (selStart && selEnd && selEnd > selStart) ? { start: selStart, end: selEnd, days: BR.daysBetween(selStart, selEnd) } : null;
  const confirmDates = () => { const dp = draftPeriod(); if (!dp) return; setPeriod(dp); setDraft({}); go('book-pads'); };

  // ---- booking draft ----
  const setDraftQty = (id, qty) => setDraft(prev => {
    const stockCap = BR.byId(id).stock - reserved(id);
    const next = { ...prev, [id]: Math.max(0, Math.min(qty, stockCap)) };
    // re-clamp toppers: never more calzones than pads in the booking
    const pads = (next.bigpad || 0) + (next.smallpad || 0) + padsInCartForPeriod(period);
    const czMax = Math.max(0, Math.min(BR.byId('calzone').stock - reserved('calzone'), pads - calzoneInCartForPeriod(period)));
    if ((next.calzone || 0) > czMax) next.calzone = czMax;
    return next;
  });
  const draftCount = () => Object.values(draft).reduce((s, q) => s + q, 0);
  const draftTotal = () => period ? Object.keys(draft).filter(id => draft[id] > 0).reduce((s, id) => s + draft[id] * BR.rentUnit(BR.byId(id), period.days), 0) : 0;
  // bulk discount for the booking-in-progress: tier on draft pads + pads already in cart for these dates
  const draftPadSub = () => period ? RENTPADS.reduce((s, id) => s + (draft[id] || 0) * BR.rentUnit(BR.byId(id), period.days), 0) : 0;
  const draftBulkCount = () => RENTPADS.reduce((s, id) => s + (draft[id] || 0), 0) + padsInCartForPeriod(period);
  const draftBulkRate = () => BR.padBulkRate(draftBulkCount());
  const draftBulkDiscount = () => Math.round(draftPadSub() * draftBulkRate());
  const draftTotalNet = () => draftTotal() - draftBulkDiscount();
  const draftLines = () => Object.keys(draft).filter(id => draft[id] > 0).map(id => ({ id, qty: draft[id], unit: BR.rentUnit(BR.byId(id), period.days) }));
  const commitBooking = () => {
    const lines = draftLines();
    if (lines.length === 0) return;
    setCart(prev => {
      let c = prev.slice();
      lines.forEach(ln => {
        const unit = BR.rentUnit(BR.byId(ln.id), period.days);
        const idx = c.findIndex(l => l.kind === 'rent' && l.id === ln.id && samePeriod(l, period));
        if (idx >= 0) c[idx] = { ...c[idx], qty: c[idx].qty + ln.qty };
        else c = c.concat([{ key: 'r' + ln.id + Date.now() + Math.random().toString(36).slice(2, 6), id: ln.id, kind: 'rent', qty: ln.qty, unit, days: period.days, period }]);
      });
      return c;
    });
    setDraft({});
    showToast('Booking added to cart');
    go('cart');
  };

  // ---- order ----
  const placeOrder = () => { const n = 4000 + Math.floor(Math.random() * 6000); setOrderNo(n); setCart([]); setDraft({}); go('done'); };

  const a = {
    go, cat, setCat, openProduct, product: BR.byId(productId), prodMode, setProdMode,
    period, availFor, bookMax, canAddCalzone, padsInCartForPeriod: () => padsInCartForPeriod(period),
    addRent, addBuy, setLineQty, removeLine, cart, cartTotal, bulkRate, bulkDiscount, padRentQty: () => padRentQtyIn(cart),
    cal: { month: calMonth, setMonth: setCalMonth, selStart, selEnd, pick },
    draftPeriod, confirmDates, draft, setDraftQty, draftCount, draftTotal, draftLines, commitBooking,
    draftBulkCount, draftBulkRate, draftBulkDiscount, draftTotalNet,
    placeOrder, orderNo, toast: showToast
  };

  const screens = {
    home: Home, shop: Shop, product: Product,
    'book-dates': BookDates, 'book-pads': BookPads, 'book-confirm': BookConfirm,
    cart: Cart, checkout: Checkout, done: Done, about: About
  };
  const Screen = screens[route] || Home;

  return (
    <div className="app">
      <Nav route={route} go={go} cartCount={cartCount} />
      <Screen a={a} key={route} />
      {toast ? <div className="toast">{toast}</div> : null}
    </div>
  );
}

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