// Your Notes — a single home for every thought parked on a video.
// Notes live per-video in state; this view flattens them into one browsable
// archive that can be grouped by date, by video, or by the tags on the
// channel the note came from.
const { useState: useStateN, useMemo: useMemoN } = React;

function NotesView({ state, dispatch }) {
  const { notes, videos, channels, hidden } = state;
  const fmt = window.SoloUtils.formatDur;

  const [q, setQ] = useStateN('');
  const [groupBy, setGroupBy] = useStateN('date');
  const [copied, setCopied] = useStateN(false);
  const [confirmDel, setConfirmDel] = useStateN(null);

  // ---- Flatten every note into one list, joined to its video + channel ----
  const all = useMemoN(() => {
    const out = [];
    for (const videoId of Object.keys(notes)) {
      const video = videos.find(v => v.id === videoId);
      if (!video || hidden.has(video.channelId)) continue;
      const channel = channels.find(c => c.id === video.channelId) || null;
      for (const n of (notes[videoId] || [])) {
        out.push({ ...n, videoId, video, channel });
      }
    }
    return out.sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0));
  }, [notes, videos, channels, hidden]);

  const query = q.trim().toLowerCase();
  const filtered = query
    ? all.filter(n =>
        (n.text || '').toLowerCase().includes(query) ||
        (n.video?.title || '').toLowerCase().includes(query) ||
        (n.channel?.name || '').toLowerCase().includes(query))
    : all;

  // ---- Grouping ----
  const groups = useMemoN(() => {
    if (filtered.length === 0) return [];

    if (groupBy === 'video') {
      const map = new Map();
      for (const n of filtered) {
        if (!map.has(n.videoId)) {
          map.set(n.videoId, { key: n.videoId, label: n.video.title, sub: n.channel?.name || '', items: [] });
        }
        map.get(n.videoId).items.push(n);
      }
      // Timed notes read best in playback order inside a video
      for (const g of map.values()) {
        g.items.sort((a, b) => {
          if (a.atSec == null && b.atSec == null) return (b.createdAt || 0) - (a.createdAt || 0);
          if (a.atSec == null) return 1;
          if (b.atSec == null) return -1;
          return a.atSec - b.atSec;
        });
      }
      return [...map.values()].sort((a, b) => b.items.length - a.items.length);
    }

    if (groupBy === 'tag') {
      const map = new Map();
      const push = (tag, n) => {
        if (!map.has(tag)) map.set(tag, { key: tag, label: tag, sub: '', items: [] });
        map.get(tag).items.push(n);
      };
      for (const n of filtered) {
        const tags = n.channel?.tags || [];
        if (tags.length === 0) push('untagged', n);
        else for (const t of tags) push(t, n);
      }
      return [...map.values()].sort((a, b) => {
        if (a.key === 'untagged') return 1;
        if (b.key === 'untagged') return -1;
        return b.items.length - a.items.length;
      });
    }

    // Default: date buckets
    const now = new Date();
    const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
    const yesterday = today - 86400000;
    const weekAgo = today - 6 * 86400000;
    const monthStart = new Date(now.getFullYear(), now.getMonth(), 1).getTime();

    const buckets = [
      { key: 'today', label: 'Today', items: [] },
      { key: 'yesterday', label: 'Yesterday', items: [] },
      { key: 'week', label: 'Earlier this week', items: [] },
      { key: 'month', label: 'Earlier this month', items: [] },
      { key: 'older', label: 'Older', items: [] },
    ];
    for (const n of filtered) {
      const t = n.createdAt || 0;
      if (t >= today) buckets[0].items.push(n);
      else if (t >= yesterday) buckets[1].items.push(n);
      else if (t >= weekAgo) buckets[2].items.push(n);
      else if (t >= monthStart) buckets[3].items.push(n);
      else buckets[4].items.push(n);
    }
    return buckets.filter(b => b.items.length > 0);
  }, [filtered, groupBy]);

  // ---- Header counts ----
  const videoCount = new Set(all.map(n => n.videoId)).size;
  const weekCutoff = Date.now() - 7 * 86400000;
  const weekCount = all.filter(n => (n.createdAt || 0) >= weekCutoff).length;

  const openNote = (n) => {
    if (n.atSec != null) dispatch({ type: 'seek', videoId: n.videoId, sec: n.atSec });
    dispatch({ type: 'route', route: { type: 'watch', id: n.videoId } });
  };

  const copyAll = () => {
    const lines = [`# SoloTube notes\n`];
    for (const g of groups) {
      lines.push(`\n## ${g.label}\n`);
      for (const n of g.items) {
        const stamp = n.atSec != null ? `[${fmt(n.atSec)}] ` : '';
        lines.push(`- ${stamp}${n.text}`);
        lines.push(`  — ${n.video.title}${n.channel ? ` · ${n.channel.name}` : ''}`);
      }
    }
    const text = lines.join('\n');
    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(text).then(() => {
        setCopied(true);
        setTimeout(() => setCopied(false), 1800);
      }).catch(() => {});
    }
  };

  const groupTabs = [
    { key: 'date', label: 'Date' },
    { key: 'video', label: 'Video' },
    { key: 'tag', label: 'Tag' },
  ];

  return (
    <main className="main">
      <div className="page-head">
        <div>
          <div className="page-eyebrow">EVERY THOUGHT YOU PARKED</div>
          <h1 className="page-title">Your notes</h1>
          <p className="page-subtitle">
            Everything you wrote while watching, in one place. Click any note to jump back
            to the exact moment that prompted it.
          </p>
        </div>
        <div className="page-head-right">
          <div className="page-stats">
            <div><span className="num">{all.length}</span>notes</div>
            <div><span className="num">{videoCount}</span>videos</div>
            <div><span className="num">{weekCount}</span>this week</div>
          </div>
        </div>
      </div>

      <div className="feed-scroll notes-hub-scroll">
        {all.length === 0 ? (
          <div className="notes-hub-empty">
            <div className="notes-hub-empty-mark">❝</div>
            <h2 className="notes-hub-empty-title">No notes yet</h2>
            <p className="notes-hub-empty-body">
              While you're watching, drop a thought at any point in the video — it gets
              pinned to that timestamp. They all collect here so you can find them later
              without scrubbing back through an hour of footage.
            </p>
          </div>
        ) : (
          <>
            <div className="notes-hub-bar">
              <div className="notes-hub-search">
                <span className="notes-hub-search-icon">⌕</span>
                <input
                  className="notes-hub-search-input"
                  placeholder="search your notes…"
                  value={q}
                  onChange={e => setQ(e.target.value)}
                  onKeyDown={e => { if (e.key === 'Escape') setQ(''); }}
                />
                {q && <button className="notes-hub-search-clear" onClick={() => setQ('')}>×</button>}
              </div>
              <div className="notes-hub-group">
                <span className="notes-hub-group-label">GROUP BY</span>
                {groupTabs.map(t => (
                  <button
                    key={t.key}
                    className={`notes-hub-tab ${groupBy === t.key ? 'active' : ''}`}
                    onClick={() => setGroupBy(t.key)}
                  >{t.label}</button>
                ))}
              </div>
              <button className="notes-hub-copy" onClick={copyAll}>
                {copied ? '✓ copied' : '⎘ copy all'}
              </button>
            </div>

            {filtered.length === 0 && (
              <div className="notes-hub-noresult">No notes match "{q}"</div>
            )}

            {groups.map(g => (
              <section className="notes-hub-group-block" key={g.key}>
                <div className="notes-hub-group-head">
                  <span className="notes-hub-group-title">
                    {groupBy === 'tag' && <span className="notes-hub-hash">#</span>}
                    {g.label}
                  </span>
                  {g.sub && <span className="notes-hub-group-sub">{g.sub}</span>}
                  <span className="notes-hub-group-count">
                    {g.items.length.toString().padStart(2, '0')}
                  </span>
                </div>

                {g.items.map(n => (
                  <div className="notes-hub-card" key={n.id}>
                    <button className="notes-hub-card-main" onClick={() => openNote(n)}>
                      <div className="notes-hub-card-top">
                        {n.atSec != null ? (
                          <span className="notes-hub-stamp">@ {fmt(n.atSec)}</span>
                        ) : (
                          <span className="notes-hub-stamp general">general</span>
                        )}
                        <span className="notes-hub-date">
                          {window.SoloUtils.timeAgo(n.createdAt, Date.now())}
                        </span>
                      </div>
                      <p className="notes-hub-text">{n.text}</p>
                      {groupBy !== 'video' && (
                        <div className="notes-hub-source">
                          {n.channel && (
                            <span className="notes-hub-mark" style={{ background: n.channel.accent }}>
                              {n.channel.mark}
                            </span>
                          )}
                          <span className="notes-hub-source-title">{n.video.title}</span>
                        </div>
                      )}
                    </button>
                    {confirmDel === n.id ? (
                      <div className="notes-hub-confirm">
                        <button
                          className="notes-hub-confirm-yes"
                          onClick={() => {
                            dispatch({ type: 'remove-note', videoId: n.videoId, id: n.id });
                            setConfirmDel(null);
                          }}
                        >delete</button>
                        <button className="notes-hub-confirm-no" onClick={() => setConfirmDel(null)}>keep</button>
                      </div>
                    ) : (
                      <button
                        className="notes-hub-del"
                        onClick={() => setConfirmDel(n.id)}
                        title="Delete note"
                      >×</button>
                    )}
                  </div>
                ))}
              </section>
            ))}

            {/* Beta tease — shared notes */}
            <section className="notes-hub-tease">
              <div className="notes-hub-tease-badge">COMING SOON</div>
              <h3 className="notes-hub-tease-title">Compare notes with a friend</h3>
              <p className="notes-hub-tease-body">
                Invite someone to a video and see both sets of notes side by side on the
                same timeline — what they caught that you missed, and the moments you
                both stopped on. Same private-by-default rules: you choose the video,
                you choose who sees it.
              </p>
            </section>
          </>
        )}
      </div>
    </main>
  );
}

window.NotesView = NotesView;
