// screens.jsx — v2 Home / Detail / Compose / Profile (group-scoped).
(function () {
  const { useState } = React;
  const { Icon, Avatar, NameLine, PostCard, ReplyCard, TrackCard, Reactions, Cover, Header, Wordmark } = window;
  const iconBtn = { background: 'none', border: 'none', cursor: 'pointer', padding: 4, display: 'flex', alignItems: 'center' };

  function Bell({ app }) {
    const T = app.theme; const n = app.notifs.unread;
    return (
      <button onClick={() => app.openNotifs()} aria-label={`通知${n > 0 ? `（未読${n}）` : ''}`} style={{ ...iconBtn, position: 'relative', color: T.sub }}>
        <Icon.sparkle size={21} />
        {n > 0 && <span style={{ position: 'absolute', top: 0, right: 0, minWidth: 8, height: 8, borderRadius: 8, background: T.accent, border: `2px solid ${T.bg}` }} />}
      </button>
    );
  }

  function HomeScreen({ app }) {
    const T = app.theme;
    return (
      <>
        <Header big={<Wordmark app={app} />} left={<button onClick={() => app.setTab('profile')} style={iconBtn}><Avatar user="you" size={30} /></button>} right={<Bell app={app} />} />
        <div>
          {app.posts.length === 0 && <div style={{ textAlign: 'center', color: T.faint, fontSize: 13.5, padding: '40px 24px', lineHeight: 1.8 }}>まだ投稿がありません。<br/>審査を突破して、最初の一曲を。</div>}
          {app.posts.map((p) => <PostCard key={p.id} post={p} onOpen={() => app.go('detail', { id: p.id })} />)}
          {app.posts.length > 0 && <div style={{ textAlign: 'center', color: T.faint, fontSize: 12.5, padding: '22px 0 12px' }}>ここが、{app.copy.appName}の全部。<br/>いい曲はリアクションで盛り上げよう。</div>}
        </div>
      </>
    );
  }

  function DetailScreen({ app, postId }) {
    const T = app.theme;
    const post = app.posts.find((p) => p.id === postId);
    if (!post) return <div style={{ padding: 40, color: T.sub }}>投稿が見つかりません。</div>;
    const track = app.trackById[post.track_id];
    return (
      <>
        <Header title="投稿" left={<button onClick={() => app.back()} style={iconBtn}><span style={{ color: T.text }}><Icon.back size={22} /></span></button>} />
        <div>
          <div style={{ padding: 16, borderBottom: `1px solid ${T.border}` }}>
            <div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
              <Avatar user={post.author} size={46} />
              <div style={{ minWidth: 0 }}><NameLine user={post.author} app={app} /><div style={{ color: T.faint, fontSize: 13 }}>{post.time}</div></div>
            </div>
            {post.text && <div style={{ color: T.text, fontSize: 17, lineHeight: 1.65, marginTop: 12 }}>{post.text}</div>}
            {track && <TrackCard track={track} />}
            {post.link_url && <window.LinkCard post={post} app={app} />}
            <Reactions target={post} type="post" app={app} />
          </div>
          <div style={{ padding: '12px 16px 6px', color: T.faint, fontSize: 12.5, fontWeight: 700 }}>リプライ（だれでも参加OK）</div>
          {(post.replies || []).length === 0 && <div style={{ padding: '8px 16px 20px', color: T.faint, fontSize: 14 }}>まだリプがありません。最初のひとことを。</div>}
          {(post.replies || []).map((r) => <ReplyCard key={r.id} reply={r} app={app} />)}
          <div style={{ height: 90 }} />
        </div>
      </>
    );
  }

  function ReplyBar({ app, postId }) {
    const T = app.theme; const [text, setText] = useState(''); const [sending, setSending] = useState(false);
    const send = async () => { const v = text.trim(); if (!v || sending) return; setSending(true); try { await app.addReply(postId, v); setText(''); } finally { setSending(false); } };
    return (
      <div style={{ position: 'absolute', left: 0, right: 0, bottom: 0, zIndex: 50, background: T.glass, backdropFilter: 'blur(18px)', WebkitBackdropFilter: 'blur(18px)', borderTop: `1px solid ${T.border}`, padding: '10px 12px 30px', display: 'flex', alignItems: 'center', gap: 10 }}>
        <Avatar user="you" size={34} />
        <input value={text} onChange={(e) => setText(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') send(); }} placeholder="リプを書く…（だれでもOK）" style={{ flex: 1, background: T.surface, border: `1px solid ${T.border}`, borderRadius: 20, padding: '10px 14px', color: T.text, fontSize: 14.5, fontFamily: 'inherit', outline: 'none' }} />
        <button onClick={send} disabled={!text.trim()} style={{ border: 'none', borderRadius: 18, padding: '9px 16px', fontWeight: 800, fontSize: 14, background: text.trim() ? T.accent : T.surface2, color: text.trim() ? '#fff' : T.faint, cursor: text.trim() ? 'pointer' : 'default', fontFamily: 'inherit' }}>リプ</button>
      </div>
    );
  }

  function ComposeScreen({ app }) {
    const T = app.theme;
    const [mode, setMode] = useState(app.sharedUrl ? 'link' : 'search');
    const [q, setQ] = useState(''); const [results, setResults] = useState([]); const [searching, setSearching] = useState(false);
    const [picked, setPicked] = useState(null); const [text, setText] = useState('');
    const [url, setUrl] = useState(app.sharedUrl || ''); const [resolved, setResolved] = useState(null); const [resolving, setResolving] = useState(false); const [rerr, setRerr] = useState('');
    // debounced song search (iTunes Search API via /api/search)
    React.useEffect(() => {
      if (mode !== 'search') return;
      const v = q.trim(); if (!v) { setResults([]); return; }
      setSearching(true);
      const id = setTimeout(async () => { try { const r = await app.searchSongs(v); setResults(r.results || []); } catch { setResults([]); } finally { setSearching(false); } }, 350);
      return () => clearTimeout(id);
    }, [q, mode]);

    const resolve = async (u) => {
      const v = (u || url).trim(); if (!v) return; setRerr(''); setResolving(true); setResolved(null);
      try { const r = await app.resolveLink(v); setResolved(r); } catch (e) { setRerr(e.message === 'unsupported_host' ? '対応サービス(Spotify/Apple/YouTube/Amazon)のリンクを貼ってください' : 'リンクを読めませんでした'); } finally { setResolving(false); }
    };
    React.useEffect(() => { if (app.sharedUrl) resolve(app.sharedUrl); }, []);

    const [posting, setPosting] = useState(false);
    const canPost = (mode === 'search' ? !!picked : !!resolved) && !posting;
    const post = async () => {
      if (!canPost) return;
      setPosting(true);
      try {
        const link = mode === 'search'
          ? { url: picked.url, title: picked.title, artist: picked.artist, image: picked.artwork, service: picked.service || 'apple' }
          : resolved;
        await app.addPostLink(link, text.trim());
        app.closeCompose(); app.setTab('home');
      } finally { setPosting(false); }
    };
    const closeC = () => { if ((text.trim() || picked || resolved || url.trim()) && !confirm('入力中の内容を破棄しますか？')) return; app.closeCompose(); };
    const tab = (k, l) => <button onClick={() => setMode(k)} style={{ flex: 1, padding: '9px', borderRadius: 10, border: `1px solid ${mode === k ? T.accent : T.border}`, background: mode === k ? T.surface2 : 'none', color: mode === k ? T.text : T.sub, fontWeight: 800, fontSize: 13, cursor: 'pointer', fontFamily: 'inherit' }}>{l}</button>;

    return (
      <div style={{ position: 'absolute', inset: 0, background: T.bg, zIndex: 80, display: 'flex', flexDirection: 'column' }}>
        <div style={{ paddingTop: 54, padding: 'max(54px, env(safe-area-inset-top)) 14px 10px', borderBottom: `1px solid ${T.border}`, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <button onClick={closeC} style={{ ...iconBtn, color: T.text }}><Icon.close size={24} /></button>
          <span style={{ fontWeight: 800, color: T.text }}>おすすめを投稿</span>
          <button onClick={post} disabled={!canPost} style={{ border: 'none', borderRadius: 20, padding: '9px 18px', fontWeight: 800, fontSize: 14.5, background: canPost ? T.accent : T.surface2, color: canPost ? '#fff' : T.faint, cursor: canPost ? 'pointer' : 'default', fontFamily: 'inherit' }}>{posting ? '…' : '投稿'}</button>
        </div>
        <div style={{ flex: 1, overflow: 'auto', padding: '14px 16px 40px' }}>
          <div style={{ display: 'flex', gap: 12 }}>
            <Avatar user="you" size={44} />
            <textarea value={text} onChange={(e) => setText(e.target.value)} rows={3} placeholder="この曲をおすすめする、ひとこと。（理由が一行あると伝わる）" style={{ flex: 1, background: 'none', border: 'none', outline: 'none', resize: 'none', color: T.text, fontSize: 16, lineHeight: 1.6, fontFamily: 'inherit', paddingTop: 8 }} />
          </div>
          {mode === 'search' && picked && <div style={{ marginLeft: 56 }}><window.LinkCard post={{ link_url: picked.url, link_title: picked.title, link_artist: picked.artist, link_image: picked.artwork, link_service: picked.service || 'apple' }} app={app} /></div>}
          {mode === 'link' && resolved && <div style={{ marginLeft: 56 }}><window.LinkCard post={{ link_url: resolved.url, link_title: resolved.title, link_artist: resolved.artist, link_image: resolved.image, link_service: resolved.service }} app={app} /></div>}

          <div style={{ display: 'flex', gap: 8, margin: '18px 0 14px' }}>{tab('search', '曲を検索')}{tab('link', 'リンクを貼る')}</div>

          {mode === 'search' ? (
            <div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, background: T.surface, border: `1px solid ${T.border}`, borderRadius: 12, padding: '9px 12px', marginBottom: 10 }}><span style={{ color: T.faint }}><Icon.search size={18} /></span><input value={q} onChange={(e) => setQ(e.target.value)} placeholder="曲名・アーティストで検索（全曲OK）" style={{ flex: 1, background: 'none', border: 'none', outline: 'none', color: T.text, fontSize: 14.5, fontFamily: 'inherit' }} /></div>
              {searching && <div style={{ color: T.faint, fontSize: 12.5, padding: '4px 2px' }}>検索中…</div>}
              {!searching && q.trim() && results.length === 0 && <div style={{ color: T.faint, fontSize: 13, padding: '10px 2px' }}>見つかりませんでした。別の言葉で試してください。</div>}
              <div style={{ display: 'flex', flexDirection: 'column' }}>{results.map((t, i) => { const on = picked && picked.url === t.url; return <button key={t.url || i} onClick={() => setPicked(t)} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '8px', borderRadius: 12, background: on ? T.surface2 : 'none', border: on ? `1px solid ${T.accent}66` : '1px solid transparent', cursor: 'pointer', textAlign: 'left', font: 'inherit' }}>{t.artwork ? <img src={t.artwork} alt="" style={{ width: 44, height: 44, borderRadius: 9, objectFit: 'cover', flexShrink: 0 }} /> : <div style={{ width: 44, height: 44, borderRadius: 9, background: T.surface2, flexShrink: 0 }} />}<div style={{ flex: 1, minWidth: 0 }}><div style={{ fontWeight: 700, color: T.text, fontSize: 14.5, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{t.title}</div><div style={{ color: T.sub, fontSize: 12.5, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{t.artist}</div></div>{on && <span style={{ color: T.accent }}><Icon.check size={20} /></span>}</button>; })}</div>
            </div>
          ) : (
            <div>
              <div style={{ color: T.faint, fontSize: 12.5, lineHeight: 1.6, marginBottom: 8 }}>Spotify / Apple Music / YouTube / Amazon の曲リンクを貼り付け（共有ボタンからでもOK）。</div>
              <div style={{ display: 'flex', gap: 8 }}>
                <input value={url} onChange={(e) => setUrl(e.target.value)} placeholder="https://open.spotify.com/track/…" style={{ flex: 1, background: T.surface, border: `1px solid ${T.border}`, borderRadius: 12, padding: '11px 12px', color: T.text, fontSize: 14, fontFamily: 'inherit', outline: 'none' }} />
                <button onClick={() => resolve()} disabled={resolving || !url.trim()} style={{ border: 'none', borderRadius: 12, padding: '0 16px', background: T.accent, color: '#fff', fontWeight: 800, cursor: 'pointer', fontFamily: 'inherit', opacity: resolving || !url.trim() ? 0.5 : 1 }}>{resolving ? '…' : '読込'}</button>
              </div>
              {rerr && <div style={{ color: '#c0392b', fontSize: 12.5, marginTop: 8 }}>{rerr}</div>}
            </div>
          )}
        </div>
      </div>
    );
  }

  function ProfileScreen({ app }) {
    const T = app.theme; const u = app.users.you; const m = app.membership || {};
    const ACCENTS = ['#d8442f', '#1f897a', '#d99a1c', '#2a4a86', '#8b5cf6', '#e0795a', '#5a8f3a'];
    const mine = app.posts.filter((p) => p.author.id === app.me.id);
    const myAlbums = app.albums || [];
    const [invite, setInvite] = useState(null);
    const issue = async () => { try { const r = await app.createInvite(); setInvite(r); try { await navigator.clipboard.writeText(r.url); } catch {} } catch (e) { alert(e.message === 'no_invites_left' ? '招待枠がありません' : 'エラー: ' + e.message); } };
    return (
      <>
        <Header title="あなた" left={<span style={{ opacity: 0 }}><Icon.back size={22} /></span>} right={<Bell app={app} />} />
        <div style={{ padding: '18px 18px 0' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
            <Avatar user="you" size={66} />
            <div style={{ flex: 1 }}><div style={{ display: 'flex', alignItems: 'center', gap: 6 }}><span style={{ fontWeight: 900, fontSize: 19, color: T.text }}>{u.name}</span>{m.passed && <span style={{ color: T.accent }}><Icon.verified size={17} /></span>}</div><div style={{ color: T.faint, fontSize: 13.5 }}>@{u.handle} · {app.copy.appName}</div></div>
          </div>

          <div style={{ marginTop: 16, padding: 16, borderRadius: 16, background: T.surface, border: `1px solid ${m.passed ? T.accent + '55' : T.border}`, display: 'flex', alignItems: 'center', gap: 14 }}>
            <div style={{ width: 46, height: 46, borderRadius: 12, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: m.passed ? `${T.accent}22` : T.surface2, color: m.passed ? T.accent : T.faint }}>{m.passed ? <Icon.badgeFill size={26} /> : <Icon.lock size={22} />}</div>
            <div style={{ flex: 1 }}><div style={{ fontWeight: 800, color: T.text, fontSize: 15 }}>{m.passed ? '審査 合格 — 投稿できます' : '審査 未合格'}</div><div style={{ color: T.sub, fontSize: 12.5, marginTop: 2 }}>{m.passed ? `ベスト ${m.exam_best}` : 'リプはOK。投稿は審査の先に。'}</div></div>
            <button onClick={() => app.startExam()} style={{ border: 'none', borderRadius: 12, padding: '9px 14px', fontWeight: 800, fontSize: 13, background: m.passed ? T.surface2 : T.accent, color: m.passed ? T.sub : '#fff', cursor: 'pointer', fontFamily: 'inherit', flexShrink: 0 }}>{m.passed ? '審査' : '受ける'}</button>
          </div>

          <div style={{ marginTop: 14, display: 'flex', gap: 8, flexWrap: 'wrap' }}>
            <button onClick={issue} style={{ flex: 1, minWidth: 150, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, padding: '11px', borderRadius: 12, border: 'none', background: T.accent, color: '#fff', fontWeight: 800, fontSize: 13.5, cursor: 'pointer', fontFamily: 'inherit' }}><Icon.link size={16} />招待リンクを発行{m.role !== 'admin' ? `（残${m.invites_remaining}）` : ''}</button>
            {m.role === 'admin' && <button onClick={() => app.openAdmin()} style={{ flex: 1, minWidth: 110, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, padding: '11px', borderRadius: 12, border: `1px solid ${T.border}`, background: T.surface, color: T.text, fontWeight: 800, fontSize: 13.5, cursor: 'pointer', fontFamily: 'inherit' }}><Icon.badge size={16} />管理</button>}
          </div>
          {invite && <div style={{ marginTop: 10, padding: 12, borderRadius: 12, background: T.surface2, border: `1px solid ${T.border}` }}><div style={{ color: T.sub, fontSize: 12, marginBottom: 5 }}>使い切り招待リンク（コピー済み）</div><div style={{ color: T.text, fontSize: 12.5, wordBreak: 'break-all', fontFamily: 'monospace' }}>{invite.url}</div></div>}

          {/* 見た目（あなた専用・端末ローカル保存） */}
          <div style={{ marginTop: 14, padding: 14, borderRadius: 14, background: T.surface, border: `1px solid ${T.border}` }}>
            <div style={{ color: T.faint, fontSize: 12.5, fontWeight: 700, marginBottom: 8 }}>見た目（あなた専用）</div>
            <div style={{ color: T.sub, fontSize: 12, marginBottom: 6 }}>テーマカラー</div>
            <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
              {ACCENTS.map((a) => <button key={a} onClick={() => app.setPref('accent', a)} aria-label={`テーマ色 ${a}`} style={{ width: 30, height: 30, borderRadius: 8, background: a, border: app.prefs.accent === a ? `2px solid ${T.text}` : '2px solid transparent', cursor: 'pointer' }} />)}
              <button onClick={() => app.setPref('accent', null)} style={{ height: 30, padding: '0 10px', borderRadius: 8, border: `1px dashed ${T.border}`, background: 'none', color: T.sub, fontSize: 11.5, fontWeight: 700, cursor: 'pointer', fontFamily: 'inherit' }}>標準に戻す</button>
            </div>
            <div style={{ color: T.sub, fontSize: 12, margin: '12px 0 6px' }}>フォント</div>
            <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
              {Object.entries(window.PF_FONTS).map(([k, f]) => { const on = (app.prefs.font || 'zen') === k; return <button key={k} onClick={() => app.setPref('font', k === 'zen' ? null : k)} style={{ padding: '7px 12px', borderRadius: 999, border: `1px solid ${on ? T.accent : T.border}`, background: on ? `${T.accent}1a` : 'none', color: T.text, fontFamily: f.css, fontSize: 13, fontWeight: 700, cursor: 'pointer' }}>{f.label}</button>; })}
            </div>
            <div style={{ color: T.faint, fontSize: 11, marginTop: 8 }}>※この端末だけの設定です（グループ全体の色は管理者が設定）。</div>
          </div>
        </div>

        <div style={{ marginTop: 20 }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '0 18px 8px' }}><div style={{ color: T.faint, fontSize: 12.5, fontWeight: 700 }}>マイアルバム</div><button onClick={() => app.openAlbumEditor(null)} style={{ display: 'flex', alignItems: 'center', gap: 5, border: 'none', background: 'none', color: T.accent, fontWeight: 800, fontSize: 13, cursor: 'pointer', fontFamily: 'inherit' }}><Icon.plus size={16} />作成</button></div>
          {myAlbums.length === 0 ? <button onClick={() => app.openAlbumEditor(null)} style={{ display: 'block', width: 'calc(100% - 36px)', margin: '0 18px', padding: '22px', borderRadius: 14, border: `1.5px dashed ${T.border}`, background: 'none', color: T.faint, fontSize: 13.5, lineHeight: 1.7, cursor: 'pointer', fontFamily: 'inherit' }}>＋ 最初のアルバムを作る<br/>好きな曲をまとめて、サブスクのリンクを添えて共有。</button> : myAlbums.map((a) => <window.AlbumCard key={a.id} album={a} app={app} />)}
        </div>

        <div style={{ marginTop: 18 }}>
          <div style={{ padding: '0 18px 8px', color: T.faint, fontSize: 12.5, fontWeight: 700 }}>あなたの投稿</div>
          {mine.length === 0 ? <div style={{ padding: '18px', textAlign: 'center', color: T.faint, fontSize: 13.5, lineHeight: 1.7 }}>{m.passed ? 'まだ投稿がありません。＋から一曲どうぞ。' : '審査に合格すると、ここに投稿が並びます。'}</div> : mine.map((p) => <PostCard key={p.id} post={p} onOpen={() => app.go('detail', { id: p.id })} />)}
        </div>

        <button onClick={() => app.logout()} style={{ margin: '20px 18px 0', width: 'calc(100% - 36px)', padding: '11px', borderRadius: 12, border: `1px solid ${T.border}`, background: 'none', color: T.faint, fontWeight: 700, fontSize: 13.5, cursor: 'pointer', fontFamily: 'inherit' }}>ログアウト</button>
        <div style={{ height: 40 }} />
      </>
    );
  }

  Object.assign(window, { HomeScreen, DetailScreen, ReplyBar, ComposeScreen, ProfileScreen });
})();
