/* MapScreen — full-bleed map + drag bottom sheet + filter rail */

function useTickingMinute(start, jitterEvery = 12000) {
  const [v, setV] = React.useState(start);
  React.useEffect(() => {
    if (start <= 0) return;
    const id = setInterval(() => {
      setV(prev => {
        if (prev <= 1) return start; // loop
        // 30% chance to tick down a minute, 10% chance to bump up (queue lengthens)
        const r = Math.random();
        if (r < 0.5) return Math.max(1, prev - 1);
        if (r < 0.65) return prev + 1;
        return prev;
      });
    }, jitterEvery);
    return () => clearInterval(id);
  }, [start, jitterEvery]);
  return v;
}

/* Pin on map — positioned absolutely */
function MapPin({ v, onClick, preset, reducedMotion, intensity, selected, dimmed }) {
  return (
    <button
      onClick={onClick}
      style={{
        position: 'absolute',
        left: `${v.map.x}%`, top: `${v.map.y}%`,
        transform: 'translate(-50%, -50%)',
        background: 'transparent', border: 'none',
        cursor: 'pointer',
        padding: 0,
        zIndex: selected ? 5 : (v.tier + 1),
        opacity: dimmed ? 0.32 : 1,
        filter: dimmed ? 'saturate(0.15)' : 'none',
        transition: 'opacity 220ms ease, filter 220ms ease',
      }}
    >
      <Halo
        tier={v.tier}
        size={selected ? 86 : 72}
        preset={preset}
        reducedMotion={reducedMotion}
        intensity={intensity}
        accepting={v.accepting && !v.paused}
        soldOut={v.tier > 0 && (v.soldOut?.length > 0) && !v.accepting}
        stale={v.stale}
        selected={selected}
      />
    </button>
  );
}

function MapScreen({
  dark,
  vendors,
  preset,
  reducedMotion,
  intensity,
  onSelectVendor,
  selectedId,
}) {
  /* Bottom sheet drag */
  const SHEET = { peek: 240, mid: 440, full: 720 };
  const [sheetH, setSheetH] = React.useState(SHEET.peek);
  const dragRef = React.useRef({ active: false, startY: 0, startH: 0 });

  const onPointerDown = (e) => {
    dragRef.current = { active: true, startY: e.clientY, startH: sheetH };
    e.currentTarget.setPointerCapture(e.pointerId);
  };
  const onPointerMove = (e) => {
    if (!dragRef.current.active) return;
    const dy = dragRef.current.startY - e.clientY;
    const next = Math.max(120, Math.min(720, dragRef.current.startH + dy));
    setSheetH(next);
  };
  const onPointerUp = () => {
    if (!dragRef.current.active) return;
    dragRef.current.active = false;
    // snap to nearest
    const candidates = [SHEET.peek, SHEET.mid, SHEET.full];
    const nearest = candidates.reduce((a, b) => Math.abs(b - sheetH) < Math.abs(a - sheetH) ? b : a);
    setSheetH(nearest);
  };

  /* Filters */
  const [filterIds, setFilterIds] = React.useState(new Set(['ordering']));
  const toggleFilter = (id) => {
    setFilterIds(prev => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id); else next.add(id);
      return next;
    });
  };
  const filteredVendors = React.useMemo(() => {
    return vendors.filter(v => {
      if (filterIds.has('ordering') && (!v.accepting || v.paused)) return false;
      if (filterIds.has('open') && v.onSite === 'not-here') return false;
      if (filterIds.has('tacos')  && !/taco/i.test(v.cuisine)) return false;
      if (filterIds.has('pizza')  && !/pizza/i.test(v.cuisine)) return false;
      if (filterIds.has('sweet')  && !/pastr|bake|dosa/i.test(v.cuisine)) return false;
      if (filterIds.has('price')  && v.priceTier && v.priceTier.length > 2) return false;
      if (filterIds.has('near')   && v.distance > 0.5) return false;
      return true;
    });
  }, [vendors, filterIds]);

  const filteredIds = new Set(filteredVendors.map(v => v.id));

  // Sort: tier desc, then aura desc; nulls (unscored) last
  const ranked = [...filteredVendors].sort((a, b) => {
    if (a.tier !== b.tier) return b.tier - a.tier;
    return (b.aura ?? -1) - (a.aura ?? -1);
  });

  return (
    <div style={{
      position: 'absolute', inset: 0,
      background: 'var(--map-bg)',
      overflow: 'hidden',
    }}>
      {/* Map base */}
      <MapCanvas dark={dark} />

      {/* Pins — unscored renders at full opacity (presence is the signal);
          filtered-out renders desaturated + dimmed (still here, just not relevant
          to the active filters). The two states are deliberately distinct. */}
      {vendors.map(v => (
        <MapPin
          key={v.id}
          v={v}
          preset={preset}
          reducedMotion={reducedMotion}
          intensity={intensity}
          selected={selectedId === v.id}
          dimmed={!filteredIds.has(v.id)}
          onClick={() => onSelectVendor(v.id)}
        />
      ))}

      {/* Top: search + filter chip rail */}
      <div style={{
        position: 'absolute', top: 56, left: 0, right: 0,
        zIndex: 30,
        display: 'flex', flexDirection: 'column', gap: 10,
        padding: '0 12px',
      }}>
        <Glass dark={dark} style={{ borderRadius: 16, padding: '11px 14px' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, color: 'var(--ink)' }}>
            <Ic.Search s={17} c="var(--ink-3)" />
            <span style={{
              flex: 1, fontFamily: 'var(--font-body)', fontSize: 15,
              color: 'var(--ink-3)',
            }}>What are you craving?</span>
            <div style={{ width: 1, height: 18, background: 'var(--ink-4)', opacity: 0.35 }}/>
            <Ic.Sliders s={16} c="var(--ink)" />
          </div>
        </Glass>

        <div
          className="no-scrollbar"
          style={{
            display: 'flex', gap: 8,
            overflowX: 'auto',
            padding: '2px 4px',
            margin: '0 -4px',
          }}
        >
          {FILTERS.map(f => (
            <FilterChip
              key={f.id}
              label={f.label}
              active={filterIds.has(f.id)}
              onClick={() => toggleFilter(f.id)}
              dark={dark}
            />
          ))}
        </div>
      </div>

      {/* Right rail: floating actions */}
      <div style={{
        position: 'absolute',
        right: 12,
        top: 200,
        display: 'flex', flexDirection: 'column', gap: 10,
        zIndex: 25,
      }}>
        <Glass dark={dark} style={{ width: 44, height: 44, borderRadius: 22, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Ic.Layers s={18} c="var(--ink)" />
        </Glass>
        <Glass dark={dark} style={{ width: 44, height: 44, borderRadius: 22, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          <Ic.Locate s={18} c="var(--accent)" />
        </Glass>
      </div>

      {/* "You" dot — center-ish */}
      <div style={{
        position: 'absolute',
        left: '46%', top: '54%',
        transform: 'translate(-50%, -50%)',
        zIndex: 4,
      }}>
        <div style={{
          width: 16, height: 16, borderRadius: '50%',
          background: '#3478F6',
          boxShadow: '0 0 0 4px rgba(52,120,246,0.22), 0 0 0 0.5px rgba(255,255,255,0.7) inset',
          border: '2.5px solid #fff',
        }}/>
      </div>

      {/* Cluster glyph demonstration — bottom-left tightly grouped */}
      <div style={{
        position: 'absolute', left: '36%', top: '74%',
        transform: 'translate(-50%, -50%)',
        zIndex: 3,
      }}>
        <HaloCluster count={3} brightestTier={3} preset={preset} reducedMotion={reducedMotion} intensity={intensity} />
      </div>

      {/* Bottom sheet */}
      <BottomSheet
        h={sheetH}
        dark={dark}
        onPointerDown={onPointerDown}
        onPointerMove={onPointerMove}
        onPointerUp={onPointerUp}
        ranked={ranked}
        totalVisible={vendors.length}
        preset={preset}
        reducedMotion={reducedMotion}
        intensity={intensity}
        onSelectVendor={onSelectVendor}
        sheetSizes={SHEET}
        setSheetH={setSheetH}
      />
    </div>
  );
}

function BottomSheet({
  h, dark, onPointerDown, onPointerMove, onPointerUp,
  ranked, totalVisible, preset, reducedMotion, intensity,
  onSelectVendor, sheetSizes, setSheetH,
}) {
  return (
    <div style={{
      position: 'absolute', left: 0, right: 0, bottom: 0,
      height: h,
      background: dark ? 'rgba(24,20,16,0.96)' : 'rgba(255,253,248,0.97)',
      backdropFilter: 'blur(24px) saturate(180%)',
      WebkitBackdropFilter: 'blur(24px) saturate(180%)',
      borderTopLeftRadius: 28, borderTopRightRadius: 28,
      borderTop: dark ? '0.5px solid rgba(255,255,255,0.08)' : '0.5px solid rgba(31,27,22,0.06)',
      boxShadow: dark
        ? '0 -16px 40px rgba(0,0,0,0.45)'
        : '0 -10px 32px rgba(31,27,22,0.10)',
      transition: 'height 220ms cubic-bezier(0.2, 0.9, 0.25, 1)',
      zIndex: 40,
      display: 'flex', flexDirection: 'column',
      overflow: 'hidden',
    }}>
      {/* Drag handle */}
      <div
        onPointerDown={onPointerDown}
        onPointerMove={onPointerMove}
        onPointerUp={onPointerUp}
        onPointerCancel={onPointerUp}
        onClick={() => {
          // tap to cycle
          const cur = h;
          const order = [sheetSizes.peek, sheetSizes.mid, sheetSizes.full];
          const idx = order.indexOf(cur);
          setSheetH(order[(idx + 1) % order.length] || sheetSizes.mid);
        }}
        style={{
          padding: '10px 0 6px',
          display: 'flex', justifyContent: 'center',
          cursor: 'grab',
          touchAction: 'none',
        }}
      >
        <div style={{
          width: 38, height: 5,
          borderRadius: 999,
          background: dark ? 'rgba(255,255,255,0.18)' : 'rgba(31,27,22,0.18)',
        }}/>
      </div>

      {/* Sheet header */}
      <div style={{ padding: '4px 20px 8px' }}>
        <div style={{
          fontFamily: 'var(--font-display)',
          fontSize: 26, lineHeight: 1.05, letterSpacing: '-0.005em',
          color: 'var(--ink)',
        }}>
          Brightest aura <span className="serif-i">nearby</span>
        </div>
        <div style={{
          marginTop: 4,
          fontSize: 12.5, color: 'var(--ink-3)',
          display: 'flex', gap: 6, alignItems: 'center',
        }}>
          <span className="mono">{ranked.length}</span>
          <span>of</span>
          <span className="mono">{totalVisible}</span>
          <span>visible · ranked by aura</span>
        </div>
      </div>

      {/* List */}
      <div className="no-scrollbar" style={{ flex: 1, overflowY: 'auto', overscrollBehavior: 'contain' }}>
        {ranked.map(v => (
          <VendorRow
            key={v.id}
            v={v}
            onClick={() => onSelectVendor(v.id)}
            preset={preset}
            reducedMotion={reducedMotion}
            intensity={intensity}
            dark={dark}
          />
        ))}
        <div style={{ height: 60 }}/>
      </div>
    </div>
  );
}

window.MapScreen = MapScreen;
window.useTickingMinute = useTickingMinute;
