/* ============================================================
   CATERING & PARKING — location-aware logistics searcher
   · Understands the three shoot locations; vendors carry real
     distances to each one
   · Book food + parking per location → flows straight onto the
     call sheet with computed meal times & per-dept park-by plan
   ============================================================ */

const CATERING_DB = [
  { id: 'c1', name: 'Ember & Rye Catering', kind: 'Full catering', cuisine: 'Cal-Mediterranean', perHead: 24, cap: 120, rating: 4.8, phone: '+1 818 555 0301', veg: true,  diets: ['vegetarian', 'vegan', 'gluten-free', 'halal'], ll: [33.9525, -118.3880] },
  { id: 'c2', name: 'La Cocina Roja Truck',  kind: 'Food truck',    cuisine: 'Tacos · birria',     perHead: 14, cap: 80,  rating: 4.6, phone: '+1 213 555 0322', veg: true,  diets: ['vegetarian', 'gluten-free'], ll: [33.9700, -118.3840] },
  { id: 'c3', name: 'Daybreak Craft Services', kind: 'Craft services', cuisine: 'Coffee · all-day snacks', perHead: 9, cap: 200, rating: 4.9, phone: '+1 818 555 0344', veg: true, diets: ['vegetarian', 'vegan', 'lactose-free', 'gluten-free'], ll: [33.9890, -118.3915] },
  { id: 'c4', name: 'Pacific Bento Co.',     kind: 'Drop-off',      cuisine: 'Japanese bento',     perHead: 18, cap: 150, rating: 4.5, phone: '+1 310 555 0367', veg: false, diets: ['vegetarian', 'lactose-free'], ll: [34.2410, -118.4290] },
  { id: 'c5', name: 'Hangar Kitchen',        kind: 'Full catering', cuisine: 'American comfort',   perHead: 21, cap: 90,  rating: 4.4, phone: '+1 818 555 0389', veg: false, diets: ['nut-free'], ll: [34.2520, -118.4090] },
  { id: 'c6', name: 'Verde Verde',           kind: 'Food truck',    cuisine: 'Vegan bowls',        perHead: 16, cap: 60,  rating: 4.7, phone: '+1 323 555 0398', veg: true,  diets: ['vegetarian', 'vegan', 'lactose-free', 'gluten-free', 'nut-free'], ll: [34.2330, -118.4020] },
];
const PARKING_DB = [
  { id: 'p1', name: 'Lot C — Studio Overflow', kind: 'Surface lot', cap: 140, cost: '$8/day',  shuttle: '10 min shuttle loop', shuttleMin: 10, ll: [33.9760, -118.3820] },
  { id: 'p2', name: 'Airpark East Apron',      kind: 'Drive-on',    cap: 60,  cost: 'Included · pass req.', shuttle: 'On site', shuttleMin: 0, ll: [34.2588, -118.4120] },
  { id: 'p3', name: 'Gravel Yard — Airway Rd', kind: 'Open yard',   cap: 90,  cost: '$5/day',  shuttle: '4 min walk', shuttleMin: 4, ll: [34.2548, -118.4185] },
  { id: 'p4', name: 'Pacoima Structure 2',     kind: 'Structure',   cap: 300, cost: '$12/day', shuttle: '15 min shuttle loop', shuttleMin: 15, ll: [34.2700, -118.4250] },
];
const HEADCOUNT = 42; /* crew + cast + standins, Day 1 */

/* ---------- dietary needs — remembered, used to sort & flag (never to hide) ---------- */
const DIETS = [
  { id: 'vegetarian', label: 'Vegetarian' },
  { id: 'vegan', label: 'Vegan' },
  { id: 'lactose-free', label: 'Lactose intolerant' },
  { id: 'gluten-free', label: 'Gluten-free' },
  { id: 'nut-free', label: 'Nut allergy' },
  { id: 'halal', label: 'Halal' },
];
const dietLabel = id => (DIETS.find(d => d.id === id) || {}).label || id;
const dietMissing = (c, diets) => (diets || []).filter(d => !(c.diets || []).includes(d));
window.SL_DIETS = DIETS;
function useDiet() {
  const [diets, setD] = useState(() => {
    return window.SLStore.get('silverlines.diet.v1', []);
  });
  const toggle = id => setD(l => {
    const n = l.includes(id) ? l.filter(x => x !== id) : [...l, id];
    window.SLStore.set('silverlines.diet.v1', n);
    return n;
  });
  return { diets, toggle };
}
/* dietary needs derived from the crew actually assigned to THIS production (their
   person profiles) — merged with the manually-added list, never hides a vendor. */
function derivedDiets() {
  try {
    const people = window.SLStore.get('silverlines.people.v1', []) || [];
    const byId = {}; people.forEach(p => { byId[p.id] = p; });
    const pid = window.PROJ_ID || 'crimson';
    let ids;
    if (pid === 'crimson') ids = window.SLStore.get('silverlines.roster.v1', []) || [];
    else { const code = (window.PROJECT && window.PROJECT.code) || ''; ids = (window.SLStore.get('silverlines.assign.v1', {}) || {})[code] || []; }
    const set = new Set();
    ids.forEach(id => ((byId[id] && byId[id].diet) || []).forEach(d => set.add(d)));
    return [...set];
  } catch (e) { return []; }
}
/* real-world distance between two [lat,lng] points, in miles (haversine) */
const milesBetween = (a, b) => {
  if (!a || !b) return 0;
  const R = 3958.8, rad = d => d * Math.PI / 180;
  const dLat = rad(b[0] - a[0]), dLng = rad(b[1] - a[1]);
  const h = Math.sin(dLat / 2) ** 2 + Math.cos(rad(a[0])) * Math.cos(rad(b[0])) * Math.sin(dLng / 2) ** 2;
  return 2 * R * Math.asin(Math.sqrt(h));
};
/* geocode any address via OpenStreetMap (no key); fall back to a stable point near LA */
async function geocodeAddr(q) {
  try {
    const r = await fetch('https://nominatim.openstreetmap.org/search?format=json&limit=1&q=' + encodeURIComponent(q + ', Los Angeles, CA'));
    const j = await r.json();
    if (j && j[0]) return { ll: [parseFloat(j[0].lat), parseFloat(j[0].lon)], real: true };
  } catch (e) {}
  let s = 0; for (let i = 0; i < q.length; i++) s = (s * 31 + q.charCodeAt(i)) % 99991;
  return { ll: [34.00 + (s % 800) / 10000, -118.46 + ((s >> 3) % 1100) / 10000], real: false };
}

/* ---------- time math (every schedule string is derived, never hand-typed twice) ---------- */
const tMin = s => { const [h, m] = String(s).split(':').map(Number); return h * 60 + (m || 0); };
const tStr = m => `${String(Math.floor(((m % 1440) + 1440) % 1440 / 60)).padStart(2, '0')}:${String(m % 60).padStart(2, '0')}`;
function mealPlan() {
  const calls = CREW_CALL.map(c => tMin(c.call));
  const first = Math.min(...calls);
  const general = tMin('07:00');
  return {
    breakfast: { t: tStr(first - 30), note: 'ready 30 min before first call' },
    lunch:     { t: tStr(general + 6 * 60), note: '6 hrs after general call' },
    wrap:      { t: tStr(general + 11 * 60), note: 'wrap bites & coffee' },
  };
}
const parkBy = (call, p) => tStr(tMin(call) - ((p && p.shuttleMin) || 0) - 10);

/* ---------- bookings, pinned per location ---------- */
function useLogistics() {
  const [bookings, setB] = useState(() => {
    return window.SLStore.get('silverlines.logistics.v1', {});
  });
  const book = (locNo, type, id) => setB(o => {
    const cur = { ...(o[locNo] || {}) };
    cur[type] = cur[type] === id ? null : id;
    const n = { ...o, [locNo]: cur };
    window.SLStore.set('silverlines.logistics.v1', n);
    return n;
  });
  return { bookings, book };
}
const bookedFood = (bookings, no) => CATERING_DB.find(c => c.id === (bookings[no] || {}).food);
const bookedPark = (bookings, no) => PARKING_DB.find(p => p.id === (bookings[no] || {}).park);

/* ---------- vendor cards ---------- */
function FoodCard({ c, d, booked, onBook, diets }) {
  const missing = dietMissing(c, diets);
  return (
    <div className={cx('rounded-xl border p-3 transition-colors', booked ? 'border-mint/40 bg-mint/5' : 'border-line bg-ink-900 hover:border-ink-600')}>
      <div className="flex items-start justify-between gap-2">
        <div className="min-w-0">
          <div className="truncate text-[13px] font-700 text-head">{c.name}</div>
          <div className="text-[11px] text-zinc-500">{c.kind} · {c.cuisine}</div>
        </div>
        <span className="shrink-0 rounded-md border border-electric/30 bg-electric/10 px-1.5 py-0.5 font-mono text-[10.5px] font-600 text-electric-soft">{d.toFixed(1)} mi</span>
      </div>
      <div className="mt-2 flex flex-wrap items-center gap-1.5 text-[10.5px]">
        <span className="rounded-full border border-line px-2 py-0.5 font-600 text-zinc-400">${c.perHead}/head</span>
        <span className={cx('rounded-full border px-2 py-0.5 font-600', c.cap >= HEADCOUNT ? 'border-line text-zinc-400' : 'border-amber/40 text-amber')}>feeds {c.cap}</span>
        <span className="rounded-full border border-line px-2 py-0.5 font-600 text-zinc-400">★ {c.rating}</span>
        {diets.length === 0 && c.veg && <span className="rounded-full border border-mint/30 px-2 py-0.5 font-600 text-mint">veg ok</span>}
        {diets.length > 0 && (missing.length === 0
          ? <span className="inline-flex items-center gap-1 rounded-full border border-mint/30 px-2 py-0.5 font-600 text-mint"><Icon name="Check" size={9} sw={3} /> covers all needs</span>
          : <span title={`May not have ${missing.map(dietLabel).join(', ')} options — call to confirm`}
              className="inline-flex items-center gap-1 rounded-full border border-amber/40 bg-amber/8 px-2 py-0.5 font-600 text-amber">
              <Icon name="TriangleAlert" size={9} /> check: {missing.map(dietLabel).join(', ')}
            </span>)}
      </div>
      <div className="mt-2.5 flex items-center justify-between gap-2">
        <a href={`tel:${c.phone.replace(/\s/g, '')}`} className="truncate font-mono text-[10.5px] text-zinc-500 hover:text-zinc-300">{c.phone}</a>
        <button onClick={onBook}
          className={cx('flex shrink-0 items-center gap-1 rounded-lg px-2.5 py-1.5 text-[11px] font-700 transition-colors',
            booked ? 'bg-mint/15 text-mint' : 'bg-cta text-cta-ink hover:bg-cta-hover')}>
          <Icon name={booked ? 'Check' : 'UtensilsCrossed'} size={11} />{booked ? 'Booked' : 'Book'}
        </button>
      </div>
    </div>
  );
}
function ParkCard({ p, d, booked, onBook }) {
  return (
    <div className={cx('rounded-xl border p-3 transition-colors', booked ? 'border-mint/40 bg-mint/5' : 'border-line bg-ink-900 hover:border-ink-600')}>
      <div className="flex items-start justify-between gap-2">
        <div className="min-w-0">
          <div className="truncate text-[13px] font-700 text-head">{p.name}</div>
          <div className="text-[11px] text-zinc-500">{p.kind} · {p.shuttle}</div>
        </div>
        <span className="shrink-0 rounded-md border border-electric/30 bg-electric/10 px-1.5 py-0.5 font-mono text-[10.5px] font-600 text-electric-soft">{d.toFixed(1)} mi</span>
      </div>
      <div className="mt-2 flex flex-wrap items-center gap-1.5 text-[10.5px]">
        <span className={cx('rounded-full border px-2 py-0.5 font-600', p.cap >= HEADCOUNT ? 'border-line text-zinc-400' : 'border-amber/40 text-amber')}>{p.cap} spots</span>
        <span className="rounded-full border border-line px-2 py-0.5 font-600 text-zinc-400">{p.cost}</span>
      </div>
      <div className="mt-2.5 flex items-center justify-end">
        <button onClick={onBook}
          className={cx('flex shrink-0 items-center gap-1 rounded-lg px-2.5 py-1.5 text-[11px] font-700 transition-colors',
            booked ? 'bg-mint/15 text-mint' : 'bg-cta text-cta-ink hover:bg-cta-hover')}>
          <Icon name={booked ? 'Check' : 'CircleParking'} size={11} />{booked ? 'Booked' : 'Book'}
        </button>
      </div>
    </div>
  );
}

/* ============================================================
   AREA MAP — pinpoint view of locations, food & parking
   ============================================================ */
function MapPin_({ pt, dim, active, children, onClick, title, z = 20 }) {
  if (!pt) return null;
  return (
    <button onClick={onClick} title={title}
      className={cx('absolute transition-opacity', dim && 'opacity-40')}
      style={{ left: pt.x, top: pt.y, transform: 'translate(-50%,-50%)', zIndex: active ? 45 : z, pointerEvents: 'auto' }}>
      {children}
    </button>
  );
}

/* ---------- real map (Leaflet + OpenStreetMap/CARTO dark tiles, no key/backend) ---------- */
function AreaMap({ locNo, setLocNo, radius, bookings, onBook, diets, custom, distOf, areaName, center }) {
  const [sel, setSel] = useState(null); /* {type, id} */
  const elRef = useRef(null), mapRef = useRef(null), circleRef = useRef(null);
  const [, setTick] = useState(0);
  const force = () => setTick(t => (t + 1) % 1e6);

  /* create the map once */
  useEffect(() => {
    if (mapRef.current || !elRef.current || !window.L) return;
    const map = L.map(elRef.current, { zoomControl: false, attributionControl: false, zoomSnap: 0.25 }).setView(center, 12);
    L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png',
      { subdomains: 'abcd', maxZoom: 19, detectRetina: true }).addTo(map);
    L.control.zoom({ position: 'topright' }).addTo(map);
    L.control.attribution({ position: 'bottomright', prefix: false })
      .addAttribution('© OpenStreetMap · © CARTO').addTo(map);
    map.on('click', () => setSel(null));
    map.on('move zoom zoomanim resize', force);
    mapRef.current = map;
    /* the container can mount at 0 height (tab/scroll); keep the map sized to it */
    let ro;
    if (window.ResizeObserver) { ro = new ResizeObserver(() => { map.invalidateSize(); force(); }); ro.observe(elRef.current); }
    const t = setTimeout(() => { map.invalidateSize(); force(); }, 120);
    force();
    return () => { clearTimeout(t); if (ro) ro.disconnect(); map.remove(); mapRef.current = null; };
  }, []);

  /* recenter + draw the real radius circle whenever the active area or radius changes */
  useEffect(() => {
    const map = mapRef.current; if (!map || !window.L) return;
    map.flyTo(center, Math.max(map.getZoom(), 11.5), { duration: 0.6 });
    if (circleRef.current) circleRef.current.remove();
    circleRef.current = L.circle(center, {
      radius: radius * 1609.34, color: 'rgb(245,127,69)', weight: 1.25,
      fillColor: 'rgb(245,127,69)', fillOpacity: 0.06, dashArray: '5 5', interactive: false,
    }).addTo(map);
    setSel(null);
    force();
  }, [center[0], center[1], radius]);

  const pt = ll => { const m = mapRef.current; if (!m || !ll) return null; const p = m.latLngToContainerPoint(ll); return { x: p.x, y: p.y }; };

  const selEntry = sel ? (sel.type === 'food' ? CATERING_DB : PARKING_DB).find(e => e.id === sel.id) : null;
  const selBooked = sel && (bookings[locNo] || {})[sel.type] === sel.id;
  const missing = selEntry && sel.type === 'food' ? dietMissing(selEntry, diets) : [];
  const selPt = selEntry && pt(selEntry.ll);
  const above = selPt && selPt.y > 150;

  return (
    <Panel pad={false}>
      <div className="relative h-[330px] overflow-hidden rounded-2xl" style={{ background: 'rgb(var(--ink-900))' }}>
        {/* the real map */}
        <div ref={elRef} className="z-0" style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0, height: '100%', width: '100%', background: 'rgb(var(--ink-900))' }} />

        {/* pin overlay — lets the map pan/zoom through, pins stay clickable */}
        <div className="absolute inset-0 z-10" style={{ pointerEvents: 'none' }}>
          {/* shoot locations */}
          {LOCATIONS.map(l => {
            const on = !custom && l.no === locNo;
            return (
              <MapPin_ key={'l' + l.no} pt={pt(l.ll)} active={on} z={25} title={l.address}
                onClick={e => { e.stopPropagation(); setLocNo(l.no); setSel(null); }}>
                <span className="flex flex-col items-center gap-1">
                  <span className={cx('flex h-8 w-8 items-center justify-center rounded-full border-2 shadow-lg transition-colors',
                    on ? 'border-electric bg-electric/25 text-electric-soft' : 'border-line bg-ink-850 text-zinc-300')}>
                    <Icon name="Clapperboard" size={14} />
                  </span>
                  <span className={cx('whitespace-nowrap rounded-md px-1.5 py-0.5 font-display text-[9.5px] shadow',
                    on ? 'bg-electric/20 text-electric-soft' : 'bg-black/60 text-zinc-300')}>{l.name}</span>
                </span>
              </MapPin_>
            );
          })}
          {/* custom area pin */}
          {custom && (
            <MapPin_ pt={pt(custom.ll)} active z={26} title={custom.addr} onClick={e => e.stopPropagation()}>
              <span className="flex flex-col items-center gap-1">
                <span className="flex h-8 w-8 items-center justify-center rounded-full border-2 border-proflow bg-proflow/25 text-proflow-soft shadow-lg">
                  <Icon name="MapPinned" size={14} />
                </span>
                <span className="max-w-[160px] truncate whitespace-nowrap rounded-md bg-proflow/20 px-1.5 py-0.5 font-display text-[9.5px] text-proflow-soft shadow">{custom.addr}</span>
              </span>
            </MapPin_>
          )}
          {/* food pins */}
          {CATERING_DB.map(c => {
            const out = distOf(c) > radius;
            const bk = (bookings[locNo] || {}).food === c.id;
            const flag = diets.length > 0 && dietMissing(c, diets).length > 0;
            return (
              <MapPin_ key={c.id} pt={pt(c.ll)} dim={out} active={sel && sel.id === c.id}
                title={`${c.name} · ${distOf(c).toFixed(1)} mi`}
                onClick={e => { e.stopPropagation(); setSel({ type: 'food', id: c.id }); }}>
                <span className={cx('relative flex h-7 w-7 items-center justify-center rounded-full border shadow-lg transition-colors',
                  bk ? 'border-mint bg-mint text-ink-950' : 'border-proflow/60 bg-ink-850 text-proflow-soft hover:border-proflow')}>
                  <Icon name="UtensilsCrossed" size={12} />
                  {flag && !bk && <span className="absolute -right-1 -top-1 flex h-3 w-3 items-center justify-center rounded-full bg-amber text-[7px] font-800 text-ink-950">!</span>}
                </span>
              </MapPin_>
            );
          })}
          {/* parking pins */}
          {PARKING_DB.map(p => {
            const out = distOf(p) > radius;
            const bk = (bookings[locNo] || {}).park === p.id;
            return (
              <MapPin_ key={p.id} pt={pt(p.ll)} dim={out} active={sel && sel.id === p.id}
                title={`${p.name} · ${distOf(p).toFixed(1)} mi`}
                onClick={e => { e.stopPropagation(); setSel({ type: 'park', id: p.id }); }}>
                <span className={cx('flex h-7 w-7 items-center justify-center rounded-lg border shadow-lg transition-colors',
                  bk ? 'border-mint bg-mint text-ink-950' : 'border-line bg-ink-850 text-zinc-300 hover:border-zinc-500')}>
                  <Icon name="CircleParking" size={13} />
                </span>
              </MapPin_>
            );
          })}
        </div>

        {/* pin popover */}
        {selEntry && selPt && (
          <div onClick={e => e.stopPropagation()}
            className="fade-up absolute z-40 w-[210px] rounded-xl border border-line bg-ink-850 p-3 shadow-2xl"
            style={{ left: Math.min(Math.max(selPt.x, 110), (elRef.current ? elRef.current.clientWidth : 320) - 110), top: selPt.y + (above ? -16 : 16), transform: 'translate(-50%,' + (above ? '-100%' : '0') + ')' }}>
            <div className="text-[12.5px] font-700 text-head">{selEntry.name}</div>
            <div className="mt-0.5 text-[10.5px] text-zinc-500">{selEntry.kind}{selEntry.cuisine ? ' · ' + selEntry.cuisine : ''}{selEntry.cost ? ' · ' + selEntry.cost : ''}</div>
            <div className="mt-1 font-mono text-[10px] text-electric-soft">{distOf(selEntry).toFixed(1)} mi from {areaName}</div>
            {missing.length > 0 && (
              <div className="mt-1.5 flex items-start gap-1 text-[10px] leading-snug text-amber">
                <Icon name="TriangleAlert" size={10} className="mt-0.5 shrink-0" /> May not have {missing.map(dietLabel).join(', ')} — call to confirm
              </div>
            )}
            <button onClick={() => { onBook(sel.type, selEntry.id, selEntry.name); }}
              className={cx('mt-2 flex w-full items-center justify-center gap-1.5 rounded-lg py-1.5 text-[11px] font-700 transition-colors',
                selBooked ? 'bg-mint/15 text-mint' : custom ? 'border border-line text-zinc-400' : 'bg-cta text-cta-ink hover:bg-cta-hover')}>
              <Icon name={selBooked ? 'Check' : 'BookmarkPlus'} size={11} />{selBooked ? 'Booked here' : custom ? 'Pick a unit to book' : 'Book for this location'}
            </button>
          </div>
        )}

        {/* legend */}
        <div className="pointer-events-none absolute bottom-2.5 left-2.5 z-30 flex items-center gap-3 rounded-lg bg-black/55 px-2.5 py-1.5 font-mono text-[9px] tracking-wide text-zinc-300 backdrop-blur-sm">
          <span className="flex items-center gap-1"><Icon name="Clapperboard" size={10} className="text-electric-soft" /> location</span>
          <span className="flex items-center gap-1"><Icon name="UtensilsCrossed" size={10} className="text-proflow-soft" /> food</span>
          <span className="flex items-center gap-1"><Icon name="CircleParking" size={10} /> parking</span>
          <span className="opacity-70">○ {radius} mi radius</span>
        </div>
      </div>
    </Panel>
  );
}

/* ============================================================
   PRE-PRODUCTION TAB
   ============================================================ */
function CateringTab({ mobile }) {
  const { bookings, book } = useLogistics();
  const { diets, toggle } = useDiet();
  const derived = derivedDiets();
  const effective = [...new Set([...derived, ...diets])];
  const [locNo, setLocNo] = useState(1);
  const [custom, setCustom] = useState(null);        /* { addr, pos } — free-hand area */
  const [addrDraft, setAddrDraft] = useState('');
  const [radius, setRadius] = useState(8);
  const [q, setQ] = useState('');
  /* empty production: no locations locked yet — don't crash, guide the user */
  if (!LOCATIONS.length) {
    return <EmptyState icon="MapPinned" title="No locations yet"
      sub="Lock a shooting location in the Location Library first — then Silverlines finds catering and parking around it and puts it on the call sheet." />;
  }
  const loc = LOCATIONS.find(l => l.no === locNo) || LOCATIONS[0];
  const areaName = custom ? custom.addr : loc.name;
  const centerLL = custom ? custom.ll : loc.ll;
  const distOf = e => milesBetween(centerLL, e.ll);
  const locate = async () => {
    const a = addrDraft.trim();
    if (!a) return;
    window.toast(`Locating “${a}”…`, 'MapPinned');
    const g = await geocodeAddr(a);
    setCustom({ addr: a, ll: g.ll });
    window.toast(g.real ? `Pinned “${a}” — distances recalculated` : `Approx-pinned “${a}” — distances recalculated`, 'MapPinned');
  };
  const pickLoc = no => { setLocNo(no); setCustom(null); setAddrDraft(''); };
  const ql = q.trim().toLowerCase();
  const food = CATERING_DB
    .filter(c => distOf(c) <= radius && (!ql || (c.name + ' ' + c.kind + ' ' + c.cuisine).toLowerCase().includes(ql)))
    .sort((a, b) => (dietMissing(a, effective).length - dietMissing(b, effective).length) || (distOf(a) - distOf(b)));
  const parks = PARKING_DB
    .filter(p => distOf(p) <= radius && (!ql || (p.name + ' ' + p.kind).toLowerCase().includes(ql)))
    .sort((a, b) => distOf(a) - distOf(b));
  const bFood = bookedFood(bookings, locNo), bPark = bookedPark(bookings, locNo);
  const meals = mealPlan();
  const onBook = (type, id, name) => {
    if (custom) { window.toast('Bookings attach to a shoot location — pick one of the three units to lock vendors', 'Info'); return; }
    book(locNo, type, id);
    const now = (bookings[locNo] || {})[type] === id;
    const icon = type === 'food' ? 'UtensilsCrossed' : 'CircleParking';
    window.toast(now ? `${name} removed from ${loc.name}` : `${name} booked for ${loc.name} — on the call sheet`, now ? 'X' : 'Check');
    window.notify && window.notify(now ? `${name} removed from ${loc.name}` : `${name} booked for ${loc.name} — call sheet updated`, icon, 'production');
  };

  return (
    <div className="space-y-4">
      {/* controls */}
      <Panel>
        <div className="flex flex-wrap items-center gap-3">
          <div className="flex flex-wrap items-center gap-1.5">
            {LOCATIONS.map(l => (
              <button key={l.no} onClick={() => pickLoc(l.no)}
                className={cx('flex items-center gap-1.5 rounded-lg border px-2.5 py-2 font-display text-[12px] transition-colors',
                  !custom && locNo === l.no ? 'border-electric/40 bg-electric/10 text-electric-soft' : 'border-line text-zinc-400 hover:text-zinc-200')}>
                <Icon name="MapPin" size={12} />{l.name}
                {(bookedFood(bookings, l.no) && bookedPark(bookings, l.no)) && <Icon name="Check" size={11} className="text-mint" />}
              </button>
            ))}
          </div>
          {/* free-hand area */}
          <div className={cx('flex min-w-[230px] flex-1 items-center gap-2 rounded-lg border px-3 py-2 transition-colors',
            custom ? 'border-proflow/40 bg-proflow/5' : 'border-line bg-ink-900')}>
            <Icon name="MapPinned" size={13} className={cx('shrink-0', custom ? 'text-proflow-soft' : 'text-zinc-500')} />
            <input value={addrDraft} onChange={e => setAddrDraft(e.target.value)} onKeyDown={e => e.key === 'Enter' && locate()}
              placeholder="Or type any address / area to search there…"
              className="min-w-0 flex-1 bg-transparent text-[12.5px] text-zinc-200 outline-none placeholder:text-zinc-600" />
            {custom
              ? <button onClick={() => pickLoc(locNo)} title="Back to shoot locations" className="shrink-0 text-[11px] font-700 text-zinc-400 hover:text-zinc-200">Clear</button>
              : null}
            <button onClick={locate} className="shrink-0 rounded-md bg-cta px-2.5 py-1 text-[11px] font-700 text-cta-ink hover:bg-cta-hover">Locate</button>
          </div>
          <div className="flex min-w-[170px] items-center gap-2">
            <Icon name="Radius" size={14} className="shrink-0 text-zinc-500" />
            <input type="range" min="1" max="10" step="0.5" value={radius} onChange={e => setRadius(+e.target.value)} className="min-w-0 flex-1 accent-electric" />
            <span className="w-[52px] shrink-0 font-mono text-[11px] text-zinc-400">≤ {radius} mi</span>
          </div>
          <div className="flex min-w-[180px] flex-1 items-center gap-2 rounded-lg border border-line bg-ink-900 px-3 py-2">
            <Icon name="Search" size={13} className="shrink-0 text-zinc-500" />
            <input value={q} onChange={e => setQ(e.target.value)} placeholder="Cuisine, vendor, lot…"
              className="min-w-0 flex-1 bg-transparent text-[12.5px] text-zinc-200 outline-none placeholder:text-zinc-600" />
          </div>
        </div>
        <div className="mt-3 flex items-center gap-2 text-[11.5px] text-zinc-500">
          <Icon name="Navigation" size={12} className="text-zinc-600" />
          Searching around <span className="font-600 text-zinc-300">{custom ? custom.addr : loc.address}</span>
          {custom && <span className="rounded-full border border-proflow/30 px-2 py-0.5 text-[10px] font-600 text-proflow-soft">custom area</span>}
        </div>
        {/* dietary needs — remembered */}
        <div className="mt-3 flex flex-wrap items-center gap-1.5 border-t border-line pt-3">
          <span className="mr-1 flex items-center gap-1.5 text-[11px] font-600 text-zinc-500"><Icon name="Salad" size={13} /> Crew dietary needs</span>
          {DIETS.map(d => {
            const fromCrew = derived.includes(d.id);
            const on = effective.includes(d.id);
            if (fromCrew) return (
              <span key={d.id} title="From an assigned crew member's profile"
                className="flex items-center gap-1.5 rounded-full border border-mint/40 bg-mint/10 px-2.5 py-1 text-[11px] font-600 text-mint">
                <Icon name="UserCheck" size={11} />{d.label}
              </span>
            );
            return (
              <button key={d.id} onClick={() => toggle(d.id)}
                className={cx('flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-[11px] font-600 transition-colors',
                  on ? 'border-mint/40 bg-mint/10 text-mint' : 'border-line text-zinc-500 hover:text-zinc-300')}>
                <span className={cx('flex h-[13px] w-[13px] items-center justify-center rounded-[4px] border', on ? 'border-mint bg-mint text-ink-950' : 'border-zinc-600 text-transparent')}>
                  <Icon name="Check" size={9} sw={3} />
                </span>
                {d.label}
              </button>
            );
          })}
          <span className="ml-auto text-[10px] text-zinc-600">Crew-profile needs auto-added · vendors flagged, never hidden</span>
        </div>
      </Panel>

      {/* area map */}
      <AreaMap locNo={locNo} setLocNo={pickLoc} radius={radius} bookings={bookings} onBook={onBook} diets={effective}
        custom={custom} distOf={distOf} areaName={areaName} center={centerLL} />

      {/* results */}
      <div className={cx('grid gap-4', mobile ? 'grid-cols-1' : 'grid-cols-2')}>
        <Panel>
          <div className="mb-3 flex items-center gap-2">
            <Icon name="UtensilsCrossed" size={15} className="text-proflow-soft" />
            <h3 className="font-display text-[15px] text-head">Food near {custom ? custom.addr : loc.name.split(' — ')[0]}</h3>
            <Chip tone="neutral">{food.length}</Chip>
          </div>
          <div className="space-y-2.5">
            {food.map(c => <FoodCard key={c.id} c={c} d={distOf(c)} diets={effective} booked={!custom && (bookings[locNo] || {}).food === c.id} onBook={() => onBook('food', c.id, c.name)} />)}
            {food.length === 0 && <div className="scan flex h-[90px] items-center justify-center rounded-xl border border-line text-[12px] text-zinc-500">Nothing within {radius} mi — widen the radius</div>}
          </div>
        </Panel>
        <Panel>
          <div className="mb-3 flex items-center gap-2">
            <Icon name="CircleParking" size={15} className="text-proflow-soft" />
            <h3 className="font-display text-[15px] text-head">Parking near {custom ? custom.addr : loc.name.split(' — ')[0]}</h3>
            <Chip tone="neutral">{parks.length}</Chip>
          </div>
          <div className="space-y-2.5">
            {parks.map(p => <ParkCard key={p.id} p={p} d={distOf(p)} booked={!custom && (bookings[locNo] || {}).park === p.id} onBook={() => onBook('park', p.id, p.name)} />)}
            {parks.length === 0 && <div className="scan flex h-[90px] items-center justify-center rounded-xl border border-line text-[12px] text-zinc-500">Nothing within {radius} mi — widen the radius</div>}
          </div>
        </Panel>
      </div>

      {/* day plan — all departments (shoot locations only) */}
      {custom ? (
        <Panel>
          <div className="flex items-center gap-2.5 text-[12.5px] text-zinc-400">
            <Icon name="Compass" size={15} className="shrink-0 text-proflow-soft" />
            Exploring <span className="font-600 text-zinc-200">{custom.addr}</span> — to lock vendors onto the call sheet, switch back to one of the three shoot locations.
          </div>
        </Panel>
      ) : (
      <Panel>
        <div className="mb-3 flex flex-wrap items-center justify-between gap-2">
          <div className="flex items-center gap-2">
            <Icon name="CalendarClock" size={15} className="text-proflow-soft" />
            <h3 className="font-display text-[15px] text-head">Day plan — {loc.name}</h3>
          </div>
          {bFood && bPark
            ? <Chip tone="mint"><Icon name="Check" size={11} /> Locked — on the call sheet</Chip>
            : <Chip tone="amber"><Icon name="TriangleAlert" size={11} /> Book food + parking to lock</Chip>}
        </div>
        <div className={cx('mb-4 grid gap-3', mobile ? 'grid-cols-1' : 'grid-cols-3')}>
          {[['Sunrise', 'Breakfast', meals.breakfast], ['Sun', 'Lunch', meals.lunch], ['Sunset', 'Wrap', meals.wrap]].map(([ic, l, m]) => (
            <div key={l} className="rounded-xl border border-line bg-ink-900 p-3">
              <div className="flex items-center gap-1.5 text-[10.5px] font-600 uppercase tracking-[0.1em] text-zinc-500"><Icon name={ic} size={12} />{l}</div>
              <div className="mt-1 font-display text-[24px] font-600 leading-none text-head">{m.t}</div>
              <div className="mt-1 text-[10.5px] text-zinc-500">{m.note}{l === 'Breakfast' && bFood ? ' · ' + bFood.name : ''}</div>
            </div>
          ))}
        </div>
        <div className="overflow-hidden rounded-xl border border-line">
          <table className="w-full text-left">
            <thead><tr className="bg-ink-900 text-[10px] uppercase tracking-[0.1em] text-zinc-500">
              <th className="px-3 py-2 font-600">Dept</th><th className="px-3 py-2 font-600">First call</th>
              <th className="px-3 py-2 font-600">Park by</th><th className="px-3 py-2 font-600">Route</th>
            </tr></thead>
            <tbody>
              {CREW_CALL.map(c => (
                <tr key={c.dept + c.name} className="border-t border-line/60">
                  <td className="px-3 py-2 text-[12px] font-600 text-zinc-200">{c.dept}</td>
                  <td className="px-3 py-2 font-mono text-[11.5px] text-zinc-300">{c.call}</td>
                  <td className="px-3 py-2 font-mono text-[11.5px] font-600 text-electric-soft">{bPark ? parkBy(c.call, bPark) : '—'}</td>
                  <td className="px-3 py-2 text-[11.5px] text-zinc-500">{bPark ? `${bPark.name} · ${bPark.shuttle}` : 'No parking booked'}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
        <p className="mt-2 text-[11px] text-zinc-600">Park-by = call time − shuttle − 10 min buffer. Vendors are a simulated database in this prototype — booking, scheduling and the call-sheet link are real.</p>
      </Panel>
      )}
    </div>
  );
}
window.CateringTab = CateringTab;

/* ============================================================
   CALL SHEET SECTION — everything booked flows in here
   ============================================================ */
function LogisticsSheet({ mobile }) {
  const { bookings } = useLogistics();
  const meals = mealPlan();
  const rows = LOCATIONS.map(l => ({ l, food: bookedFood(bookings, l.no), park: bookedPark(bookings, l.no) }));
  const missing = rows.filter(r => !r.food || !r.park).length;
  return (
    <SheetSection icon="UtensilsCrossed" title="Catering & Parking"
      right={<span className="font-mono text-[10.5px] text-zinc-500">BF {meals.breakfast.t} · LUNCH {meals.lunch.t} · WRAP {meals.wrap.t}</span>}>
      <div className={cx('grid gap-3', mobile ? 'grid-cols-1' : 'grid-cols-3')}>
        {rows.map(({ l, food, park }) => (
          <div key={l.no} className="rounded-xl border border-line bg-ink-900 p-3">
            <div className="flex items-center gap-1.5 text-[10.5px] font-600 uppercase tracking-[0.1em] text-zinc-500"><Icon name="MapPin" size={11} />{l.name}</div>
            <div className="mt-2 flex items-start gap-2">
              <Icon name="UtensilsCrossed" size={13} className={cx('mt-0.5 shrink-0', food ? 'text-mint' : 'text-zinc-600')} />
              {food
                ? <div className="min-w-0"><div className="truncate text-[12px] font-600 text-zinc-200">{food.name}</div>
                    <div className="font-mono text-[10px] text-zinc-500">{milesBetween(l.ll, food.ll).toFixed(1)} mi · ${food.perHead}/head · {food.phone}</div></div>
                : <span className="text-[11.5px] text-zinc-600">No catering booked</span>}
            </div>
            <div className="mt-2 flex items-start gap-2">
              <Icon name="CircleParking" size={13} className={cx('mt-0.5 shrink-0', park ? 'text-mint' : 'text-zinc-600')} />
              {park
                ? <div className="min-w-0"><div className="truncate text-[12px] font-600 text-zinc-200">{park.name}</div>
                    <div className="font-mono text-[10px] text-zinc-500">{park.cost} · {park.shuttle} · park by {parkBy(CREW_CALL.reduce((a, c) => tMin(c.call) < tMin(a.call) ? c : a).call, park)} for first call</div></div>
                : <span className="text-[11.5px] text-zinc-600">No parking booked</span>}
            </div>
          </div>
        ))}
      </div>
      {missing > 0 && (
        <div className="no-print mt-3 flex items-center gap-2 rounded-lg border border-amber/30 bg-amber/8 px-3 py-2 text-[12px] text-amber">
          <Icon name="TriangleAlert" size={13} />{missing} location{missing === 1 ? '' : 's'} unbooked — set in Pre-Production → Catering &amp; Parking.
        </div>
      )}
    </SheetSection>
  );
}
window.LogisticsSheet = LogisticsSheet;
