// Home / Today screen + Wait Times list
(function(){
const { COLORS, waitColor, PaperBg, Stamp, StampPill, Card, Caption, Display, Body,
  PerforatedDivider, Icon, Sparkline, BulletProgress, BarProgress } = window.PH365_UI;
const { ATTRACTIONS, LANDS, TODAY, ACHIEVEMENTS } = window.PH365;

// ─────────────────────────────────────────────────────────────
// HOME / TODAY
// ─────────────────────────────────────────────────────────────
function HomeScreen({ onSelectAttraction, onTabChange }) {
  // Always read from window.PH365 so live-data swaps refresh us
  const ATTRACTIONS = window.PH365.ATTRACTIONS;
  const ACHIEVEMENTS = window.PH365.ACHIEVEMENTS;
  const TODAY = window.PH365.TODAY;
  const USER = window.PH365.USER || {};

  // Pick rides under 30 min that are currently open, sorted ascending
  const sortedShort = ATTRACTIONS
    .filter(a => a.isOpen !== false && a.wait != null && a.wait > 0 && a.wait < 30)
    .sort((a, b) => a.wait - b.wait)
    .slice(0, 5);

  // Show the achievement closest to unlocking (highest fraction, not unlocked)
  const inProgress = [...ACHIEVEMENTS]
    .filter(a => !a.unlocked && a.total > 0)
    .sort((a, b) => (b.progress / b.total) - (a.progress / a.total))[0];

  const greeting = USER.isGuest
    ? 'Welcome to the parks'
    : `Hi, ${USER.name?.split(' ')[0] || 'Member'}`;

  return (
    <div style={{ padding: '12px 16px 100px' }}>
      {/* Date header */}
      <div style={{ marginTop: 8, marginBottom: 18 }}>
        <Display italic size={32}>{TODAY.date}</Display>
        <Caption style={{ marginTop: 6 }}>{greeting}</Caption>
      </div>

      {/* Today's stamp counters */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginBottom: 18 }}>
        <Card style={{ padding: '14px 16px', textAlign: 'left' }}>
          <Stamp value={TODAY.ridesToday} unit="today" size={42} />
          <Caption style={{ marginTop: 6 }}>Rides</Caption>
        </Card>
        <Card style={{ padding: '14px 16px', textAlign: 'left' }}>
          <Stamp value={TODAY.ridesYear} unit="ytd" size={42} />
          <Caption style={{ marginTop: 6 }}>This year</Caption>
        </Card>
      </div>

      {/* Park Day sits directly under the day's counters: it is the thing you
          tap when you arrive, and the counters are what it fills in. */}
      <div style={{ marginBottom: 18 }}>
        {window.ParkDayHomeCard ? <window.ParkDayHomeCard /> : null}
      </div>

      <PerforatedDivider label="Shortest waits right now" />
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: 12, marginBottom: 20 }}>
        {sortedShort.length > 0 ? (
          sortedShort.map(a => (
            <RideCardCompact key={a.id} attraction={a} onClick={() => onSelectAttraction(a.id)} />
          ))
        ) : window.PH365_QT?.lastFetchedAt ? (
          <Card style={{ padding: 14, textAlign: 'center' }}>
            <Caption>No rides under 30 min open right now</Caption>
          </Card>
        ) : (
          // Skeleton placeholders while queue-times hasn't fetched yet.
          // Matches RideCardCompact dimensions so the layout doesn't jump.
          <>
            {Array.from({ length: 4 }).map((_, i) => <SkeletonRow key={i} delay={i * 80} />)}
            <Caption style={{ textAlign: 'center', marginTop: 4 }}>
              Loading live waits from queue-times.com…
            </Caption>
          </>
        )}
      </div>

      {inProgress && (
        <>
          <PerforatedDivider label="Closest achievement" />
          <Card onClick={() => onTabChange?.('profile')} style={{ marginTop: 12, padding: 14, cursor: 'pointer' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
              <div style={{
                width: 30, height: 30, borderRadius: '50%',
                border: `1.5px solid ${COLORS.mustard}`,
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                color: COLORS.mustard, fontFamily: 'Fraunces', fontWeight: 700, fontSize: 16,
              }}>{inProgress.glyph || '★'}</div>
              <div style={{ flex: 1 }}>
                <Body size={15} weight={600}>{inProgress.name}</Body>
                <Caption style={{ marginTop: 2 }}>{inProgress.progress} of {inProgress.total}</Caption>
              </div>
            </div>
            <BarProgress value={inProgress.progress} total={inProgress.total} color={COLORS.mustard} />
            {inProgress.desc && (
              <Body size={11.5} color={COLORS.inkSoft} style={{ marginTop: 8 }}>{inProgress.desc}</Body>
            )}
          </Card>
        </>
      )}

      {/* Tip card — switch to live wait data */}
      {sortedShort.length > 0 && (
        <Card style={{ marginTop: 18, padding: '14px 16px', background: COLORS.paper }}>
          <div style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
            <Icon name="sparkle" size={18} color={COLORS.teal} />
            <div style={{ flex: 1 }}>
              <Caption color={COLORS.teal} style={{ marginBottom: 4 }}>Right now</Caption>
              <Body size={13}>
                <strong>{sortedShort[0].name}</strong> is the shortest wait at <strong>{sortedShort[0].wait} min</strong>.
                {USER.isGuest && ' Sign in to start logging your rides.'}
              </Body>
            </div>
          </div>
        </Card>
      )}
    </div>
  );
}

// Skeleton row used while queue-times is still fetching. Matches
// RideCardCompact's height so swap-in doesn't shift the layout.
function SkeletonRow({ delay = 0 }) {
  return (
    <div style={{
      background: COLORS.paperDeep,
      border: `1px solid ${COLORS.paperEdge}`,
      borderRadius: 12,
      padding: '12px 14px',
      display: 'flex',
      alignItems: 'center',
      gap: 12,
      animation: `pulse 1.4s ease-in-out ${delay}ms infinite`,
    }}>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ height: 14, width: '62%', background: COLORS.paperEdge, borderRadius: 4, opacity: 0.55 }} />
        <div style={{ height: 10, width: '38%', background: COLORS.paperEdge, borderRadius: 4, opacity: 0.4, marginTop: 6 }} />
      </div>
      <div style={{
        width: 56, height: 28, borderRadius: 6,
        background: COLORS.paperEdge, opacity: 0.45,
      }} />
    </div>
  );
}

function RideCardCompact({ attraction, onClick }) {
  const land = LANDS[attraction.land];
  return (
    <Card onClick={onClick} style={{ padding: '12px 14px' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <Body size={14.5} weight={600} style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
            {attraction.name}
          </Body>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 4 }}>
            <Caption style={{ letterSpacing: '0.1em' }}>{land.name}</Caption>
            {attraction.favorite && (
              <>
                <span style={{ color: COLORS.paperEdge, fontSize: 10 }}>·</span>
                <BulletProgress value={attraction.favoriteScore} total={8} color={COLORS.teal} dotSize={5} />
              </>
            )}
          </div>
        </div>
        <StampPill attraction={attraction} size={22} />
      </div>
    </Card>
  );
}

// ─────────────────────────────────────────────────────────────
// WAIT TIMES LIST
// ─────────────────────────────────────────────────────────────
function WaitsScreen({ onSelectAttraction }) {
  const [filter, setFilter] = React.useState('all');
  const [sort, setSort] = React.useState('wait');
  // Direction is per-sort; tapping the active sort flips it. Defaults
  // chosen so the first impression is sensible: wait ascending (shortest
  // first), recent descending (newest first), land ascending (A-Z).
  const [waitDir, setWaitDir] = React.useState('asc');
  const [expanded, setExpanded] = React.useState(null);
  const [query, setQuery] = React.useState('');

  // Read live so re-renders pick up live-data swaps
  const ATTRACTIONS = window.PH365.ATTRACTIONS;
  const LANDS = window.PH365.LANDS;

  const FILTERS = [
    { id: 'all',      label: 'All' },
    { id: 'dlr',      label: 'Disneyland' },
    { id: 'dca',      label: 'California Adventure' },
    { id: 'open',     label: 'Open Now' },
    { id: 'short',    label: '< 30 min' },
    { id: 'fav',      label: 'Favorites' },
  ];

  let list = [...ATTRACTIONS];
  if (filter === 'dlr')   list = list.filter(a => LANDS[a.land]?.park === 'DLR');
  if (filter === 'dca')   list = list.filter(a => LANDS[a.land]?.park === 'DCA');
  if (filter === 'open')  list = list.filter(a => a.isOpen !== false);
  if (filter === 'short') list = list.filter(a => a.wait != null && a.wait > 0 && a.wait < 30);
  if (filter === 'fav')   list = list.filter(a => a.favorite);

  // Free-text name search (case-insensitive substring). Applied after the
  // filter chip so search narrows within the active filter.
  if (query.trim()) {
    const q = query.trim().toLowerCase();
    list = list.filter(a => (a.name || '').toLowerCase().includes(q));
  }

  // Hide closed rides + rides with no qt data ("Show", "Walkthrough" with null wait) by default,
  // unless we're showing 'all' AND user picked a sort other than 'wait'.
  if (filter !== 'all') list = list.filter(a => a.queueTimesId != null);

  if (sort === 'wait') {
    // Push null/missing waits to the bottom regardless of direction so
    // closed/un-mapped rides don't crowd the top of either order.
    const dir = waitDir === 'asc' ? 1 : -1;
    list.sort((a, b) => {
      const av = a.wait, bv = b.wait;
      if (av == null && bv == null) return 0;
      if (av == null) return 1;
      if (bv == null) return -1;
      return (av - bv) * dir;
    });
  }
  if (sort === 'land') list.sort((a, b) => (LANDS[a.land]?.name ?? '').localeCompare(LANDS[b.land]?.name ?? ''));

  return (
    <div style={{ paddingBottom: 100 }}>
      {/* Sticky filter strip */}
      <div style={{
        position: 'sticky',
        top: 0,
        zIndex: 5,
        background: COLORS.paper,
        backgroundImage: `linear-gradient(${COLORS.paper}f5, ${COLORS.paper}f0)`,
        padding: '12px 0 10px',
        borderBottom: `1px solid ${COLORS.paperEdge}`,
      }}>
        <div style={{ padding: '0 16px 8px' }}>
          <Display size={26}>Wait Times</Display>
        </div>
        <div style={{ padding: '0 16px 8px' }}>
          <div style={{ position: 'relative' }}>
            <input
              type="text"
              value={query}
              onChange={e => setQuery(e.target.value)}
              placeholder="Search rides…"
              style={{
                width: '100%',
                padding: '8px 32px 8px 32px',
                borderRadius: 10,
                border: `1px solid ${COLORS.paperEdge}`,
                background: COLORS.paperDeep,
                fontFamily: 'Manrope, sans-serif',
                fontSize: 13,
                color: COLORS.ink,
                outline: 'none',
                boxSizing: 'border-box',
              }}
            />
            <div style={{ position: 'absolute', left: 10, top: 9, pointerEvents: 'none' }}>
              <Icon name="target" size={14} color={COLORS.inkSoft} />
            </div>
            {query && (
              <button
                onClick={() => setQuery('')}
                aria-label="Clear search"
                style={{
                  position: 'absolute', right: 6, top: 6,
                  background: 'transparent', border: 'none', cursor: 'pointer',
                  padding: 4, display: 'flex',
                }}
              >
                <Icon name="close" size={14} color={COLORS.inkSoft} />
              </button>
            )}
          </div>
        </div>
        <div style={{
          display: 'flex',
          gap: 6,
          overflowX: 'auto',
          padding: '0 16px',
          scrollbarWidth: 'none',
        }}>
          {FILTERS.map(f => (
            <FilterChip key={f.id} active={filter === f.id} onClick={() => setFilter(f.id)}>
              {f.label}
            </FilterChip>
          ))}
        </div>
        <div style={{ display: 'flex', gap: 12, padding: '8px 16px 0', alignItems: 'center' }}>
          <Caption>Sort:</Caption>
          {['wait', 'land', 'recent'].map(s => {
            const isActive = sort === s;
            // Wait is the only direction-toggleable sort right now —
            // tapping it while already active flips asc <-> desc.
            const onClick = () => {
              if (s === 'wait' && isActive) {
                setWaitDir(d => (d === 'asc' ? 'desc' : 'asc'));
              } else {
                setSort(s);
              }
            };
            const label = s === 'wait'
              ? `Wait ${waitDir === 'asc' ? '↑' : '↓'}`
              : s === 'land' ? 'Land' : 'Recent';
            return (
              <button key={s} onClick={onClick}
                title={s === 'wait' ? 'Tap again to flip direction' : undefined}
                style={{
                  border: 'none',
                  background: 'transparent',
                  padding: 0,
                  cursor: 'pointer',
                  fontFamily: 'Manrope, sans-serif',
                  fontSize: 12,
                  fontWeight: isActive ? 700 : 500,
                  color: isActive ? COLORS.ink : COLORS.inkSoft,
                  textTransform: 'uppercase',
                  letterSpacing: '0.1em',
                  borderBottom: isActive ? `1.5px solid ${COLORS.ink}` : '1.5px solid transparent',
                  paddingBottom: 2,
                }}>
                {label}
              </button>
            );
          })}
          <div style={{ flex: 1 }} />
          <Caption style={{ color: COLORS.inkSoft }}>{list.length} rides</Caption>
        </div>
      </div>

      <div style={{ padding: '12px 16px', display: 'flex', flexDirection: 'column', gap: 8 }}>
        {list.map(a => (
          <WaitRow
            key={a.id}
            attraction={a}
            expanded={expanded === a.id}
            onToggle={() => setExpanded(expanded === a.id ? null : a.id)}
            onOpen={() => onSelectAttraction(a.id)}
          />
        ))}
      </div>
    </div>
  );
}

function FilterChip({ active, children, onClick }) {
  return (
    <button onClick={onClick} style={{
      flexShrink: 0,
      padding: '6px 12px',
      borderRadius: 100,
      background: active ? COLORS.ink : 'transparent',
      color: active ? COLORS.paper : COLORS.ink,
      border: `1px solid ${active ? COLORS.ink : COLORS.paperEdge}`,
      fontFamily: 'Manrope, sans-serif',
      fontSize: 12,
      fontWeight: 600,
      cursor: 'pointer',
      letterSpacing: '0.02em',
    }}>{children}</button>
  );
}

function WaitRow({ attraction, expanded, onToggle, onOpen }) {
  const land = LANDS[attraction.land];
  return (
    <div style={{
      background: COLORS.paperDeep,
      border: `1px solid ${COLORS.paperEdge}`,
      borderRadius: 12,
      overflow: 'hidden',
      transition: 'background 0.2s',
    }}>
      <div onClick={onToggle} style={{
        padding: '12px 14px',
        display: 'flex',
        alignItems: 'center',
        gap: 10,
        cursor: 'pointer',
      }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <Body size={15} weight={600}>{attraction.name}</Body>
          <div style={{ display: 'flex', gap: 8, alignItems: 'center', marginTop: 3 }}>
            <Caption>{land.name}</Caption>
            {attraction.favorite && <Icon name="starFilled" size={12} color={COLORS.mustard} />}
          </div>
        </div>
        <StampPill attraction={attraction} size={24} />
        <Icon name={expanded ? 'chevronUp' : 'chevronDown'} size={16} color={COLORS.inkSoft} />
      </div>
      {expanded && (
        <div style={{
          padding: '12px 14px 14px',
          borderTop: `1px dashed ${COLORS.paperEdge}`,
          background: COLORS.paper,
        }}>
          {attraction.type === 'Show' ? (
            <Body size={12} color={COLORS.inkSoft} style={{ marginBottom: 12 }}>
              Entertainment — see the official Disneyland app for showtimes.
            </Body>
          ) : (
            <div style={{ display: 'flex', gap: 16, alignItems: 'center', marginBottom: 12 }}>
              <div style={{ flex: 1 }}>
                <Caption style={{ marginBottom: 4 }}>Today's wait curve</Caption>
                {attraction.history && attraction.history.length > 0 ? (
                  <Sparkline points={attraction.history} width={170} height={42} color={waitColor(attraction.wait)} />
                ) : (
                  <Caption color={COLORS.inkSoft}>Collecting data…</Caption>
                )}
              </div>
              <div style={{ textAlign: 'right' }}>
                <Caption>Now</Caption>
                <Stamp value={attraction.wait} unit="min" size={22} color={waitColor(attraction.wait)} />
              </div>
            </div>
          )}
          <div style={{ display: 'flex', gap: 8 }}>
            <PrimaryButton onClick={onOpen} style={{ flex: 1 }}>View Ride</PrimaryButton>
            {attraction.type !== 'Show' && (
              <SecondaryButton onClick={(e) => {
                e.stopPropagation();
                window.PH365_ACTIONS?.dropQueuePin?.({
                  attractionId: attraction.id, postedWait: attraction.wait,
                }).catch(err => console.warn(err));
              }}>
                <Icon name="pin" size={14} color={COLORS.ink} />
                <span style={{ marginLeft: 4 }}>Drop pin</span>
              </SecondaryButton>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

function PrimaryButton({ children, onClick, style = {} }) {
  return (
    <button onClick={onClick} style={{
      background: COLORS.teal,
      color: COLORS.paper,
      border: 'none',
      borderRadius: 10,
      padding: '10px 14px',
      fontFamily: 'Manrope, sans-serif',
      fontSize: 13,
      fontWeight: 600,
      cursor: 'pointer',
      letterSpacing: '0.02em',
      boxShadow: 'inset 0 1px 0 rgba(255,255,255,0.18)',
      ...style,
    }}>{children}</button>
  );
}
function SecondaryButton({ children, onClick, style = {} }) {
  return (
    <button onClick={onClick} style={{
      background: COLORS.paper,
      color: COLORS.ink,
      border: `1px solid ${COLORS.paperEdge}`,
      borderRadius: 10,
      padding: '10px 14px',
      fontFamily: 'Manrope, sans-serif',
      fontSize: 13,
      fontWeight: 600,
      cursor: 'pointer',
      display: 'inline-flex',
      alignItems: 'center',
      ...style,
    }}>{children}</button>
  );
}

Object.assign(window, { HomeScreen, WaitsScreen, PrimaryButton, SecondaryButton, RideCardCompact });
})();
