// Feed — list of video rows, with optional section grouping (NEW vs WATCHED)
const { useMemo: useMemoFeed, useState: useStateFeed } = React;

function MobileChannelPills({ channels, hidden, route, dispatch }) {
  const visible = channels.filter(c => !hidden.has(c.id));
  const activeId = route.type === 'channel' ? route.id : null;
  const isAll = route.type !== 'channel';
  return (
    <div className="m-ch-pills">
      <button
        className={`m-ch-pill ${isAll ? 'active' : ''}`}
        onClick={() => dispatch({ type: 'route', route: { type: 'feed', feed: 'all' } })}
      >All</button>
      {visible.map(c => (
        <button
          key={c.id}
          className={`m-ch-pill ${activeId === c.id ? 'active' : ''}`}
          onClick={() => dispatch({ type: 'route', route: { type: 'channel', id: c.id } })}
        >
          <span className="m-ch-dot" style={{ background: c.accent }}></span>
          {c.name.length > 15 ? c.name.split(/\s+/)[0] : c.name}
        </button>
      ))}
    </div>
  );
}

function VideoRow({ idx, video, channel, watched, onOpen, isNewBadge, settings, fav, onToggleFav, isArchived, onToggleArchive }) {
  const ts = video.publishedAt;
  const now = window.SOLO_DATA.NOW;
  const isNew = !watched && !video.watched;
  return (
    <button
      className={`v-row ${watched ? 'watched' : ''} ${isNew ? 'new' : ''} ${fav ? 'fav' : ''} ${settings?.viewIndices === false ? 'no-idx' : ''}`}
      onClick={() => onOpen(video.id)}
    >
      {settings?.viewIndices !== false && <div className="v-index">{String(idx + 1).padStart(2, '0')}</div>}
      <div className="v-thumb">
        <window.Thumbnail video={video} channel={channel} generated={settings?.thumbnails === 'generated'} />
        {settings?.progressBars !== false && watched && video.progress < 1 && (
          <div className="v-thumb-progress" style={{ width: `${video.progress * 100}%` }}></div>
        )}
        {watched && <div className="v-thumb-watched">watched</div>}
        <div className="v-thumb-dur">{video.duration}</div>
      </div>
      <div className="v-meta">
        <div className="v-channel-line">
          <span style={{
            display:'inline-block', width:8, height:8, background: channel.accent,
            marginRight:2, verticalAlign:0
          }}></span>
          <span>{video.sourceName || channel.name}</span>
          <span className="sep">·</span>
          <span>{window.SoloUtils.timeAgo(ts, now)}</span>
        </div>
        <div className="v-title">{video.title}</div>
        {settings?.videoSnippets && video.description && (
          <div className="v-snippet">{video.description.replace(/\n+/g, ' ').trim().slice(0, 160).replace(/\s\S*$/, '') + '…'}</div>
        )}
        <div className="v-sub">
          <span className="v-sub-item"><span className="label">DUR</span> {video.duration}</span>
          <span className="v-sub-item"><span className="label">VIEWS</span> {video.views}</span>
          {watched && video.progress < 1 && (
            <span className="v-sub-item"><span className="label">PROGRESS</span> {Math.round(video.progress*100)}%</span>
          )}
        </div>
      </div>
      <div className="v-row-right">
        {isNewBadge && <div className="v-tag new">NEW</div>}
        {onToggleFav && (
          <span
            className={`v-fav ${fav ? 'on' : ''}`}
            role="button"
            title={fav ? 'Remove from favorites' : 'Add to favorites'}
            onClick={(e) => { e.stopPropagation(); onToggleFav(video.id); }}
          >{fav ? '★' : '☆'}</span>
        )}
        {onToggleArchive && (
          <span
            className={`v-archive ${isArchived ? 'on' : ''}`}
            role="button"
            title={isArchived ? 'Unarchive — return to feed' : 'Archive — hide from feed'}
            onClick={(e) => { e.stopPropagation(); onToggleArchive(video.id); }}
          >{isArchived ? '⊕' : '⊗'}</span>
        )}
      </div>
    </button>
  );
}

function Feed({ state, dispatch }) {
  const { videos, channels, watched, hidden, route, dimWatched, settings, favorites, archived } = state;
  const channelsById = useMemoFeed(() => {
    const m = {}; for (const c of channels) m[c.id] = c; return m;
  }, [channels]);

  // Archived videos for the current scope (channel / tag / all)
  const archivedList = useMemoFeed(() => {
    let v = videos.filter(x => !hidden.has(x.channelId) && archived.has(x.id));
    if (route.type === 'channel') v = v.filter(x => x.channelId === route.id);
    if (route.type === 'tag') {
      const ok = new Set(channels.filter(c => (c.tags || []).includes(route.tag)).map(c => c.id));
      v = v.filter(x => ok.has(x.channelId));
    }
    return v.sort((a,b) => b.publishedAt - a.publishedAt);
  }, [videos, hidden, archived, route, channels]);

  // Determine which videos to show (exclude archived from main view)
  const list = useMemoFeed(() => {
    let v = videos.filter(x => !hidden.has(x.channelId) && !archived.has(x.id));
    if (route.type === 'channel') v = v.filter(x => x.channelId === route.id);
    if (route.type === 'tag') {
      const ok = new Set(channels.filter(c => (c.tags || []).includes(route.tag)).map(c => c.id));
      v = v.filter(x => ok.has(x.channelId));
    }
    if (route.type === 'feed' && route.feed === 'new') v = v.filter(x => !watched.has(x.id) && !x.watched);
    if (route.type === 'feed' && route.feed === 'watched') v = v.filter(x => watched.has(x.id) || x.watched);
    if (route.type === 'feed' && route.feed === 'favorites') v = v.filter(x => favorites.has(x.id));
    return v.sort((a,b) => b.publishedAt - a.publishedAt);
  }, [videos, watched, hidden, route, channels, favorites, archived]);

  // Split into NEW (top, unwatched) and EARLIER (watched, below)
  const isAll = route.type === 'feed' && route.feed === 'all';
  const isTag = route.type === 'tag';
  const channel = route.type === 'channel' ? channelsById[route.id] : null;

  const newOnes = list.filter(v => !watched.has(v.id) && !v.watched);
  const watchedOnes = list.filter(v => watched.has(v.id) || v.watched);

  const [activeTab, setActiveTab] = useStateFeed('all');
  const tabFiltered = useMemoFeed(() => {
    if (activeTab === 'new') return list.filter(v => !watched.has(v.id) && !v.watched);
    if (activeTab === 'watched') return list.filter(v => watched.has(v.id) || v.watched);
    if (activeTab === 'archived') return archivedList;
    return list;
  }, [list, archivedList, watched, activeTab]);

  const openVideo = (id) => dispatch({ type: 'route', route: { type: 'watch', id } });
  const toggleFav = (id) => dispatch({ type: 'toggle-favorite', id });
  const toggleArchive = (id) => dispatch({ type: archived.has(id) ? 'unarchive-video' : 'archive-video', id });

  // Determine which list rendering to use
  const splitView = isAll || route.type === 'channel' || isTag;

  return (
    <main className="main">
      <MobileChannelPills channels={channels} hidden={hidden} route={route} dispatch={dispatch} />
      {channel ? (
        <ChannelHead channel={channel} videos={list} watched={watched} dispatch={dispatch} state={state}/>
      ) : route.type === 'tag' ? (
        <TagHead state={state} dispatch={dispatch} list={list} />
      ) : (
        <FeedHead state={state} dispatch={dispatch} />
      )}

      {settings.filterBar && (
      <div className="filter-bar">
        <div className="filter-tabs">
          <button className={`filter-tab ${activeTab==='all'?'active':''}`} onClick={() => setActiveTab('all')}>
            All <span className="count">({list.length})</span>
          </button>
          <button className={`filter-tab ${activeTab==='new'?'active':''}`} onClick={() => setActiveTab('new')}>
            New <span className="count">({newOnes.length})</span>
          </button>
          <button className={`filter-tab ${activeTab==='watched'?'active':''}`} onClick={() => setActiveTab('watched')}>
            Watched <span className="count">({watchedOnes.length})</span>
          </button>
          {archivedList.length > 0 && (
            <button className={`filter-tab ${activeTab==='archived'?'active':''}`} onClick={() => setActiveTab('archived')}>
              Archived <span className="count">({archivedList.length})</span>
            </button>
          )}
        </div>
        <div className="filter-right">
          <button
            className={`filter-action dim-toggle ${dimWatched ? 'on' : ''}`}
            onClick={() => dispatch({ type: 'toggle-dim' })}
            title="Toggle dim-watched"
          >
            <span className="checkbox"></span>
            <span>dim watched</span>
          </button>
          <button className="filter-action" onClick={() => dispatch({ type: 'mark-all-read' })}>
            mark all read
          </button>
        </div>
      </div>
      )}

      <div className="feed-scroll">
        {splitView && activeTab === 'all' ? (
          <>
            {newOnes.length > 0 && (
              <>
                {settings.sectionHeaders && (
                  <div className="feed-section-head">
                    <div className="feed-section-title"><span className="dot-new"></span>NEW · UNWATCHED ({newOnes.length})</div>
                  </div>
                )}
                {newOnes.map((v, i) => (
                  <VideoRow
                    key={v.id} idx={i}
                    video={v} channel={channelsById[v.channelId]}
                    watched={false}
                    isNewBadge={i < 3 && (window.SOLO_DATA.NOW - v.publishedAt) < 2 * 24 * 60 * 60 * 1000}
                    onOpen={openVideo}
                    settings={settings}
                    fav={favorites.has(v.id)} onToggleFav={toggleFav}
                    isArchived={false} onToggleArchive={toggleArchive}
                  />
                ))}
              </>
            )}
            {watchedOnes.length > 0 && (
              <>
                {settings.sectionHeaders && (
                  <div className="feed-section-head">
                    <div className="feed-section-title">EARLIER · WATCHED ({watchedOnes.length})</div>
                  </div>
                )}
                {watchedOnes.map((v, i) => (
                  <VideoRow
                    key={v.id} idx={newOnes.length + i}
                    video={v} channel={channelsById[v.channelId]}
                    watched={true}
                    onOpen={openVideo}
                    settings={settings}
                    fav={favorites.has(v.id)} onToggleFav={toggleFav}
                    isArchived={false} onToggleArchive={toggleArchive}
                  />
                ))}
              </>
            )}
          </>
        ) : (
          <>
            {tabFiltered.length === 0 && (
              <div style={{padding: '80px 0', textAlign: 'center', fontFamily: 'var(--ff-mono)', fontSize: 12, color: 'var(--ink-3)', letterSpacing: '0.08em'}}>
                NOTHING HERE.
              </div>
            )}
            {tabFiltered.map((v, i) => (
              <VideoRow
                key={v.id} idx={i}
                video={v} channel={channelsById[v.channelId]}
                watched={watched.has(v.id) || v.watched}
                onOpen={openVideo}
                settings={settings}
                fav={favorites.has(v.id)} onToggleFav={toggleFav}
                isArchived={archived.has(v.id)} onToggleArchive={toggleArchive}
              />
            ))}
          </>
        )}
      </div>
    </main>
  );
}

// Top of "all channels" / "new" / "watched" views
function FeedHead({ state, dispatch }) {
  const { route, videos, watched, hidden, channels, settings } = state;
  const visible = videos.filter(v => !hidden.has(v.channelId));
  const newCount = visible.filter(v => !watched.has(v.id) && !v.watched).length;
  const channelCount = channels.filter(c => !hidden.has(c.id)).length;

  const title = route.feed === 'all' ? 'All Channels' :
                route.feed === 'new' ? 'Unwatched' :
                route.feed === 'favorites' ? 'Favorites' : 'Watched';
  const eyebrow = route.feed === 'all' ? 'YOUR FEED, SORTED BY RECENT' :
                  route.feed === 'new' ? 'SOMETHING NEW TO WATCH' :
                  route.feed === 'favorites' ? 'THE ONES YOU STARRED' :
                  'YOUR HISTORY';

  return (
    <div className="page-head feed-page-head">
      <div>
        {settings.pageEyebrow && <div className="page-eyebrow">{eyebrow}</div>}
        <h1 className="page-title">{title}</h1>
        {settings.pageSubtitle && (
          <p className="page-subtitle">
            A quiet, intentional feed. Only what you subscribed to, sorted by date. No suggestions, no recommendations, no algorithm.
          </p>
        )}
      </div>
      <div className="page-head-right">
        {settings.pageStats && (
          <div className="page-stats">
            <div><span className="num">{channelCount}</span>channels</div>
            <div><span className="num">{newCount}</span>new</div>
            <div><span className="num">{visible.length}</span>total</div>
          </div>
        )}
        {settings.inbox && <window.Notifications state={state} dispatch={dispatch} />}
      </div>
    </div>
  );
}

function ChannelHead({ channel, videos, watched, dispatch, state }) {
  const newCount = videos.filter(v => !watched.has(v.id) && !v.watched).length;
  const lastUpload = videos[0];
  const lastUploadAgo = lastUpload ? window.SoloUtils.timeAgo(lastUpload.publishedAt, window.SOLO_DATA.NOW) : '—';
  const tags = channel.tags || [];
  const [confirmRemove, setConfirmRemove] = React.useState(false);
  const [refreshing, setRefreshing] = React.useState(false);
  const [refreshNote, setRefreshNote] = React.useState(null);
  const canRefresh = !!(channel.uploadsPlaylistId || /^UC[\w-]{20,}$/.test(channel.id));
  const refresh = async () => {
    if (refreshing) return;
    setRefreshing(true);
    setRefreshNote(null);
    try {
      const u = new URL('/api/channel-videos', window.location.origin);
      if (channel.uploadsPlaylistId) u.searchParams.set('uploadsPlaylistId', channel.uploadsPlaylistId);
      u.searchParams.set('channelId', channel.id);
      const r = await fetch(u);
      const body = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(body?.error || `HTTP ${r.status}`);
      const incoming = body.videos || [];
      const existing = new Set(videos.map(v => v.id));
      const fresh = incoming.filter(v => !existing.has(v.id)).length;
      dispatch({ type: 'merge-videos', videos: incoming });
      setRefreshNote(fresh > 0 ? `${fresh} new` : 'up to date');
    } catch (err) {
      setRefreshNote('failed');
    } finally {
      setRefreshing(false);
      setTimeout(() => setRefreshNote(null), 2400);
    }
  };
  const { settings } = state;
  return (
    <div className="ch-head">
      <div className="ch-mark" style={{ background: channel.accent }}>{channel.mark}</div>
      <div>
        <div className="ch-name">{channel.name}</div>
        {settings.pageSubtitle && (
          <div className="ch-handle">{channel.handle} · joined {channel.joined} · {channel.subs} subscribers</div>
        )}
        {settings.pageSubtitle && <p className="ch-desc">{channel.desc}</p>}
        <div className="ch-tags">
          {tags.map(t => (
            <button key={t}
              className="tag-chip"
              onClick={() => dispatch({ type: 'route', route: { type: 'tag', tag: t } })}
              title={`Open #${t}`}
            >
              <span className="hash">#</span>{t}
              <span
                className="tag-x"
                onClick={(e) => { e.stopPropagation(); dispatch({ type: 'remove-tag', channelId: channel.id, tag: t }); }}
                title="Remove tag"
              >×</span>
            </button>
          ))}
          <button className="tag-chip tag-add" onClick={() => dispatch({ type: 'open-tag-editor', channelId: channel.id })}>
            + tag
          </button>
        </div>
      </div>
      <div>
        {settings.pageStats && (
          <div className="ch-stats">
            <div className="row"><span>videos</span><b>{videos.length.toString().padStart(2, '0')}</b></div>
            <div className="row"><span>unwatched</span><b style={{color: newCount > 0 ? 'var(--new)' : undefined}}>{newCount.toString().padStart(2, '0')}</b></div>
            <div className="row"><span>last upload</span><b>{lastUploadAgo}</b></div>
          </div>
        )}
        <div style={{marginTop: settings.pageStats ? 18 : 0, display:'flex', gap: 8, justifyContent: 'flex-end', alignItems: 'center'}}>
          {settings.inbox && <window.Notifications state={state} dispatch={dispatch} />}
          {canRefresh && (
            <button
              className="ch-refresh-btn"
              onClick={refresh}
              disabled={refreshing}
              title="Check for new uploads"
            >
              {refreshing ? '… refreshing' : (refreshNote ? `↻ ${refreshNote}` : '↻ refresh')}
            </button>
          )}
          {confirmRemove ? (
            <div className="ch-remove-confirm">
              <span>Remove this channel?</span>
              <button className="yes" onClick={() => { setConfirmRemove(false); dispatch({type:'remove-channel', channelId: channel.id}); }}>remove</button>
              <button className="no" onClick={() => setConfirmRemove(false)}>cancel</button>
            </div>
          ) : (
            <button className="ch-remove-btn" onClick={() => setConfirmRemove(true)} title="Remove channel">
              ✕ remove
            </button>
          )}
        </div>
      </div>
    </div>
  );
}

function TagHead({ state, dispatch, list }) {
  const { channels, hidden, route, watched, settings } = state;
  const tag = route.tag;
  const inTag = channels.filter(c => !hidden.has(c.id) && (c.tags || []).includes(tag));
  const newCount = list.filter(v => !watched.has(v.id) && !v.watched).length;
  return (
    <div className="page-head">
      <div>
        {settings.pageEyebrow && <div className="page-eyebrow">TAG · A SLICE OF YOUR FEED</div>}
        <h1 className="page-title">#{tag}</h1>
        {settings.pageSubtitle && (
          <p className="page-subtitle">
            {inTag.length} channel{inTag.length === 1 ? '' : 's'} tagged with #{tag}. Videos sorted by recent.
          </p>
        )}
        <div className="ch-tags" style={{marginTop: 14}}>
          {inTag.map(c => (
            <button key={c.id}
              className="tag-chip tag-chip-channel"
              onClick={() => dispatch({ type: 'route', route: { type: 'channel', id: c.id } })}>
              <span className="tag-dot" style={{background: c.accent}}></span>
              {c.name}
            </button>
          ))}
        </div>
      </div>
      <div className="page-head-right">
        {settings.pageStats && (
          <div className="page-stats">
            <div><span className="num">{inTag.length}</span>channels</div>
            <div><span className="num">{newCount}</span>new</div>
            <div><span className="num">{list.length}</span>total</div>
          </div>
        )}
        {settings.inbox && <window.Notifications state={state} dispatch={dispatch} />}
      </div>
    </div>
  );
}

window.Feed = Feed;
window.VideoRow = VideoRow;
