﻿/* ============================================================================
 * Wildy ??Wild ?덈툕 (寃뚯엫 怨듭떇 ?덊럹?댁? ?? Phase 1B-W rev2)
 * ----------------------------------------------------------------------------
 *   ?먮옒 ?몄뒪? ?쇰뱶泥섎읆 寃뚯떆臾쇰쭔 ?섏뿴?덉?留? ?ъ슜?먭? "寃뚯엫 怨듭떇 ?덊럹?댁?
 *   媛숈? 寃뚯엫 ?덈툕" ?ㅼ쓣 ?붿껌 ??4 ?뱀뀡?쇰줈 ?ъ꽕怨?
 *
 *     1) ?뱼 怨듭떇 怨듭? 쨌 ?낅뜲?댄듃  (admin/怨듭떇 寃뚯떆臾?
 *     2) ?뱲 怨듬왂 쨌 媛?대뱶          (posts.type IN ('guide','tip','review'))
 *     3) ?뮠 ?쇱씠釉?梨꾪똿 (???⑥씪)  (?ㅼ씠踰??쒕씪留??ㅼ떆媛?諛섏쓳 ??
 *     4) ?뤇截?梨꾪똿諛?/ ?뚰떚諛?       (chat_rooms 紐⑸줉, 5踰?LoL 梨꾨꼸 ??
 *
 *   ?ъ슜:
 *     <window.WildyComponents.WildDetailScreen
 *        supabaseClient={...} user={user} wildId="lol"
 *        lang="ko"
 *        onBack={...} onOpenPost={(idx, posts) => ...}
 *        onOpenChat={(room) => ...}    // 梨꾪똿諛??대┃
 *        onOpenComposer={(wildId) => ...}  // 寃뚯떆臾??묒꽦
 *     />
 *
 *   湲濡쒕쾶 ?몄텧:
 *     window.WildyComponents.WildDetailScreen
 *     window.WildyComponents.FollowButton  (?ъ궗??
 * ========================================================================= */
(function (global) {
  'use strict';

  if (typeof React === 'undefined') {
    console.error('[wild-detail.jsx] React not loaded');
    return;
  }
  const { useState, useEffect, useMemo, useRef, useCallback } = React;

  const POSTS_PAGE = 12; // 而ㅻ??덊떚 ?쇰뱶 臾댄븳 ?ㅽ겕濡??섏씠吏 ?ш린

  function localize(g, lang) {
    if (!g) return '';
    if (lang === 'en' && g.title_en) return g.title_en;
    if (lang === 'ja' && g.title_ja) return g.title_ja;
    if (lang === 'zh' && g.title_zh) return g.title_zh;
    if (lang === 'id' && g.title_id) return g.title_id;
    return g.name;
  }

  function relativeTime(iso) {
    if (!iso) return '';
    const d = new Date(iso);
    const diff = Date.now() - d.getTime();
    const m = Math.floor(diff / 60000);
    if (m < 1) return '방금';
    if (m < 60) return `${m}분 전`;
    const h = Math.floor(m / 60);
    if (h < 24) return `${h}시간 전`;
    const days = Math.floor(h / 24);
    if (days < 7) return `${days}일 전`;
    return d.toLocaleDateString('ko-KR', { month: 'short', day: 'numeric' });
  }

  function withTimeout(promise, ms, fallback) {
    return Promise.race([
      promise,
      new Promise(resolve => setTimeout(() => resolve(fallback), ms)),
    ]);
  }

  const ROOM_TYPE_LABEL = {
    notice:  { label: '怨듭?',     emoji: '?뱼', cls: 'bg-amber-100 text-amber-700' },
    free:    { label: '?ㅽ뵂梨꾪똿', emoji: '?뮠', cls: 'bg-sky-100 text-sky-700' },
    meetup:  { label: '?뚰떚諛?,   emoji: '?렜', cls: 'bg-emerald-100 text-emerald-700' },
    social:  { label: '洹몃９',     emoji: '?뫁', cls: 'bg-violet-100 text-violet-700' },
    recruit: { label: '湲몃뱶',     emoji: '?룿', cls: 'bg-rose-100 text-rose-700' },
    private: { label: '鍮꾧났媛?,   emoji: '?뵏', cls: 'bg-slate-200 text-slate-700' },
  };

  // ?곕え 梨꾪똿諛?(chat_rooms 鍮꾩뼱?덉쓣 ???쒖뿰??
  const SAMPLE_ROOMS = [
    { id: 'sample-1', name: '?먯쑀??겕 ?뚰떚諛?,  room_type: 'meetup',  member_count: 128, last_message_at: new Date().toISOString() },
    { id: 'sample-2', name: '????쒗뤏 援ы빐??, room_type: 'free',    member_count: 76,  last_message_at: new Date().toISOString() },
    { id: 'sample-3', name: '?덈꼍 ??겕 湲몃뱶',   room_type: 'recruit', member_count: 42,  last_message_at: new Date().toISOString() },
    { id: 'sample-4', name: '?곗뼱 ?곸듅 ?곌뎄??, room_type: 'social',  member_count: 33,  last_message_at: new Date().toISOString() },
  ];

  // ???????????????????????????????????????????????????????????
  // FollowButton ???ъ궗??  // ???????????????????????????????????????????????????????????
  // FollowButton ????媛吏 紐⑤뱶 吏??
  //   1) ?먯껜 紐⑤뱶 (onToggle ?놁쓬): ?먭린媛 DB INSERT/DELETE 吏곸젒 ?섑뻾 (legacy)
  //   2) ?꾩엫 紐⑤뱶 (onToggle ?덉쓬): 遺紐?App.toggleFollow) 媛 DB ??梨낆엫吏怨?  //      followedGames ?꾩뿭 ?곹깭??媛깆떊 ???ъ씠?쒕컮 "??Wild" 利됱떆 ?곕룞.
  //   ???ъ씠?쒕컮 ?곕룞???꾩슂??怨?WildDetailScreen)? 諛섎뱶??onToggle ?ъ슜.
  function FollowButton({ supabaseClient, user, wildId, initialFollowing, source = 'manual', onFollowChanged, size = 'md', onToggle }) {
    const delegated = typeof onToggle === 'function';
    const [isFollowing, setIsFollowing] = useState(Boolean(initialFollowing));
    const [loading, setLoading] = useState(false);
    const [resolved, setResolved] = useState(initialFollowing !== undefined);

    // ?꾩엫 紐⑤뱶: 遺紐④? initialFollowing ?쇰줈 ??긽 理쒖떊 ?곹깭 ?몄떆 (followedGames
    //   蹂寃???props 媛깆떊) ??濡쒖뺄 state 瑜?prop ??留욎떠 sync.
    useEffect(() => {
      if (delegated) setIsFollowing(Boolean(initialFollowing));
    }, [delegated, initialFollowing]);

    useEffect(() => {
      // ?꾩엫 紐⑤뱶?먯꽌??DB 吏곸젒 fetch ??????遺紐?App) 媛 followedGames 濡쒕뱶 梨낆엫.
      if (delegated || resolved || !supabaseClient || !user?.id || !wildId) return;
      let active = true;
      (async () => {
        try {
          const { data } = await supabaseClient
            .from('wild_subscriptions').select('id')
            .eq('user_id', user.id).eq('wild_id', wildId).maybeSingle();
          if (active) { setIsFollowing(Boolean(data)); setResolved(true); }
        } catch {}
      })();
      return () => { active = false; };
    }, [delegated, supabaseClient, user?.id, wildId, resolved]);

    const toggle = async () => {
      if (loading) return;

      // ?꾩엫 紐⑤뱶 ??App.toggleFollow 媛 DB ? followedGames ????泥섎━.
      // ?먯껜 DB ?묒뾽쨌?숆???state 媛깆떊 ?쇱젅 ????(遺紐④? followedGames 媛깆떊
      // ??initialFollowing prop 媛깆떊 ????useEffect 濡?isFollowing sync).
      if (delegated) {
        onToggle(wildId);
        return;
      }

      // ?먯껜 紐⑤뱶 (legacy ?명솚)
      if (!user?.id) { setIsFollowing(v => !v); onFollowChanged && onFollowChanged(!isFollowing); return; }
      setLoading(true);
      const was = isFollowing;
      setIsFollowing(!was);
      onFollowChanged && onFollowChanged(!was);
      const tag = `[FollowButton] ${was ? 'DELETE' : 'INSERT'} user=${user.id} wild=${wildId}`;
      try {
        if (!supabaseClient) return;
        if (was) {
          // DELETE ??.select()濡??곹뼢 row ?뚯닔??寃利? RLS/?대? 鍮꾧뎄?낆쑝濡?0 row 硫??먮윭 ?꾨떂.
          const { data, error } = await supabaseClient
            .from('wild_subscriptions')
            .delete()
            .eq('user_id', user.id)
            .eq('wild_id', wildId)
            .select('id');
          if (error) throw error;
          const rows = Array.isArray(data) ? data.length : 0;
          console.info(tag, rows === 0 ? '??0 rows (?대? 鍮꾧뎄???먮뒗 RLS ?꾪꽣) ???숆????곹깭 ?좎?' : `??deleted ${rows} row`);
        } else {
          const { data, error } = await supabaseClient
            .from('wild_subscriptions')
            .insert({ user_id: user.id, wild_id: wildId, source })
            .select('id');
          if (error) {
            const code = error.code || '';
            if (code === '23505' || String(error.message || '').includes('duplicate')) {
              console.info(tag, '???대? ?붾줈??以?(臾댄빐)');
            } else if (code === '23503') {
              console.warn(tag, '??FK ?꾨컲(23503) ??留덉씠洹몃젅?댁뀡 028 誘몄쟻?? ?몄뀡 ?쒖젙 ?좎?.');
            } else {
              throw error;
            }
          } else {
            console.info(tag, `??inserted ${Array.isArray(data) ? data.length : '?'} row`);
          }
        }
      } catch (e) {
        console.error(tag, 'FAILED', { code: e?.code, message: e?.message, details: e?.details, hint: e?.hint });
        setIsFollowing(was);
        onFollowChanged && onFollowChanged(was);
      } finally { setLoading(false); }
    };

    const sizeCls = size === 'sm' ? 'px-3 py-1.5 text-xs' : size === 'lg' ? 'px-6 py-3 text-sm' : 'px-4 py-2 text-sm';

    return (
      <button
        onClick={toggle} disabled={loading}
        className={`rounded-full font-bold transition disabled:opacity-60 ${sizeCls} ${
          isFollowing
            ? 'border-2 border-slate-200 bg-white text-slate-600 hover:border-rose-200 hover:text-rose-500'
            : 'bg-wildy-ink text-white hover:-translate-y-0.5 shadow-ink'
        }`}
      >
        {loading ? '...' : isFollowing ? '?붾줈??以? : '+ ?붾줈??}
      </button>
    );
  }

  // ???????????????????????????????????????????????????????????
  // SectionHeader ??4媛??뱀뀡 怨듭슜
  // ???????????????????????????????????????????????????????????
  function SectionHeader({ icon, title, onMore }) {
    return (
      <div className="mb-3 flex items-center justify-between">
        <h2 className="font-display text-lg font-black text-wildy-ink flex items-center gap-2">
          <span>{icon}</span><span>{title}</span>
        </h2>
        {onMore && (
          <button onClick={onMore} className="text-xs text-slate-500 hover:text-wildy-ink">
            ?붾낫湲???          </button>
        )}
      </div>
    );
  }

  // ???????????????????????????????????????????????????????????
  // WildDetailScreen ??硫붿씤
  // ???????????????????????????????????????????????????????????
  function WildDetailScreen({ supabaseClient, user, wildId, lang = 'ko', onBack, onOpenPost, onOpenChat, onOpenComposer, onNavigate, followedGames, onToggleFollow }) {
    const [wild, setWild] = useState(null);
    // ?붾줈???곹깭 = App.followedGames ?⑥씪 吏꾩떎. ?먯껜 DB fetch / 濡쒖뺄 state X.
    //   (?댁쟾: setIsFollowing(Boolean(s)) 濡?蹂꾨룄 ?숆린?????ъ씠?쒕컮? 遺덉씪移?諛쒖깮)
    const isFollowing = useMemo(
      () => Array.isArray(followedGames) && followedGames.includes(wildId),
      [followedGames, wildId]
    );
    const [notices, setNotices] = useState([]);   // 怨듭?/?낅뜲?댄듃 (admin author)
    const [guides, setGuides] = useState([]);     // 怨듬왂 (type=guide/tip/review)
    const [rooms, setRooms] = useState([]);       // 梨꾪똿諛?    const [posts, setPosts] = useState([]);       // ?쇰컲 寃뚯떆臾??쇰뱶 (洹?寃뚯엫)
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState('');
    const [joiningLive, setJoiningLive] = useState(false);
    const [createOpen, setCreateOpen] = useState(false);
    const [roomsRefreshTick, setRoomsRefreshTick] = useState(0);
    // ????寃뚯엫 ?섏씠吏 ?듯빀 ?섎ː (2026-05-15): ?쇰뱶/怨듭떇/梨꾪똿/硫ㅻ쾭 ?⑥씪 吏꾩엯.
    //   湲곕낯 = ?쇰뱶 (而ㅻ??덊떚 + 怨듬왂). DEMO_MODE ??GameHubPage 濡??대갚?섎?濡?    //   ?ш린 ??? 踰좏?(??DB) ?ъ슜?먮쭔 遊?
    const [tab, setTab] = useState('feed');       // feed | official | chat | members
    // 而ㅻ??덊떚 ?쇰뱶 臾댄븳 ?ㅽ겕濡?(#3)
    const [postsHasMore, setPostsHasMore] = useState(false);
    const [postsLoadingMore, setPostsLoadingMore] = useState(false);
    const postsOffsetRef = useRef(0);           // DB?먯꽌 媛?몄삩 row ??(range 怨꾩궛??
    const excludeIdsRef = useRef(new Set());    // 怨듭?/怨듬왂???대? ?몄텧??post id (以묐났 諛⑹?)
    const feedSentinelRef = useRef(null);       // IntersectionObserver 媛먯? 吏??
    // 梨꾪똿諛??대┃ ??sample?대㈃ 臾댁떆, ?ㅼ젣 UUID硫??낆옣
    const handleRoomClick = (r) => {
      if (!r || String(r.id).startsWith('sample-')) return;
      onOpenChat && onOpenChat({
        id: r.id,
        name: r.name,
        type: 'group',
        roomType: r.room_type,
        wild,
        isReal: true,
      });
    };

    // 梨꾪똿諛??앹꽦 ?꾨즺 ??利됱떆 洹?諛⑹쑝濡??낆옣
    const handleRoomCreated = (roomId, roomName) => {
      setRoomsRefreshTick(t => t + 1);
      onOpenChat && onOpenChat({
        id: roomId,
        name: roomName,
        type: 'group',
        wild,
        isReal: true,
      });
    };

    // ?쇱씠釉?梨꾪똿 ?낆옣: ?ㅼ젣 ?몄뀡 ?뺤씤 ??join_wild_main_chat RPC
    //   ??user prop? stale 媛????supabaseClient.auth.getSession()?쇰줈 ?ㅼ젣 ?몄뀡 ?뺤씤.
    //   ??RPC ?ㅽ뙣?대룄 ?ъ슜?먮? 留됱? ?딆쓬 ??媛??諛⑹쑝濡?graceful ?대갚 (alert X).
    const fallbackLiveRoom = () => {
      onOpenChat && onOpenChat({
        id: `live-${wildId}`, name: `${title} ?쇱씠釉?,
        room_type: 'free', wild_id: wildId, wild, isLive: true,
      });
    };
    const enterLiveChat = async () => {
      if (joiningLive) return;
      if (!supabaseClient) { fallbackLiveRoom(); return; }
      setJoiningLive(true);
      try {
        // ?ㅼ젣 ?몄뀡 ?뺤씤 (user prop ?좊ː X ???몄뀡 留뚮즺/遺덉씪移?諛⑹뼱)
        let hasSession = false;
        try {
          const { data } = await supabaseClient.auth.getSession();
          hasSession = Boolean(data?.session?.user);
        } catch {}
        if (!hasSession) {
          // 吏꾩쭨 鍮꾨줈洹몄씤 = ?곕え 媛??諛?(濡쒓렇??媛뺤슂 X)
          fallbackLiveRoom();
          return;
        }
        const { data: roomId, error } = await supabaseClient.rpc('join_wild_main_chat', { p_wild_id: wildId });
        if (error) throw error;
        if (!roomId) throw new Error('no room id');
        onOpenChat && onOpenChat({
          id: roomId,
          name: `${title} 硫붿씤`,
          room_type: 'free',
          wild_id: wildId,
          wild,
          isLive: true,
          isReal: true,
        });
      } catch (e) {
        // RPC ?ㅽ뙣 (留덉씠洹몃젅?댁뀡 誘몄쟻??/ ?쇱떆 ?ㅻ쪟) ???ъ슜??留됱? ?딄퀬 媛??諛??대갚
        console.warn('[WildDetailScreen] enterLiveChat fallback:', e?.message || e);
        fallbackLiveRoom();
      } finally {
        setJoiningLive(false);
      }
    };

    // Wild + ?붾줈??+ 4?뱀뀡 ?곗씠???숈떆 濡쒕뵫
    useEffect(() => {
      if (!wildId) return;
      let active = true;
      (async () => {
        try {
          if (!supabaseClient) {
            setWild({ id: wildId, name: wildId, emoji: '?렜', short_description: '?곕え 紐⑤뱶', member_count: 0 });
            setRooms(SAMPLE_ROOMS);
            setLoading(false);
            return;
          }

          const wildPromise = supabaseClient.from('wilds').select('*').eq('id', wildId).maybeSingle();
          // ?붾줈???곹깭??App.followedGames 媛 ?⑥씪 吏꾩떎 ??蹂꾨룄 fetch ?쒓굅.
          //   湲곗〈 subPromise ???ъ씠?쒕컮? 遺덉씪移?留뚮뱶???먯씤?댁뿀??(App 媛 媛깆떊?대룄
          //   ?ш린 isFollowing state 媛 ?먮룞 sync ????.
          // 怨듭?: admin author or type='discussion' but treat as notice
          const noticePromise = supabaseClient
            .from('posts')
            .select('id,text,image_urls,star_count,comment_count,created_at,author_id,game_tag,type,author:users!author_id(display_name,username,is_admin)')
            .eq('game_tag', wildId).eq('is_deleted', false).eq('visibility', 'public')
            .order('created_at', { ascending: false }).limit(10);
          // 怨듬왂: type IN ('guide','tip','review')
          const guidePromise = supabaseClient
            .from('posts')
            .select('id,text,image_urls,star_count,comment_count,created_at,author_id,game_tag,type,author:users!author_id(display_name,username)')
            .eq('game_tag', wildId).eq('is_deleted', false).eq('visibility', 'public')
            .in('type', ['guide', 'tip', 'review'])
            .order('star_count', { ascending: false }).limit(5);
          // 梨꾪똿諛? chat_rooms wild_id, group, active, not private
          const roomPromise = supabaseClient
            .from('chat_rooms')
            .select('id,name,room_type,member_count,description,last_message_at,is_private,is_active')
            .eq('wild_id', wildId).eq('type', 'group').eq('is_active', true).eq('is_private', false)
            .order('last_message_at', { ascending: false, nullsFirst: false }).limit(10);
          // ?쇰컲 寃뚯떆臾??쇰뱶: ?대떦 寃뚯엫??紐⑤뱺 type, 理쒖떊????怨듭?/怨듬왂 ?쒖쇅?섍퀬 ?쒖떆??寃?(#3 臾댄븳 ?ㅽ겕濡?1?섏씠吏)
          const postPromise = supabaseClient
            .from('posts')
            .select('id,text,image_urls,video_url,star_count,comment_count,created_at,author_id,game_tag,type,author:users!author_id(display_name,username,avatar,is_admin)')
            .eq('game_tag', wildId).eq('is_deleted', false).eq('visibility', 'public')
            .order('created_at', { ascending: false }).range(0, POSTS_PAGE - 1);

          const [
            wildRes,
            noticeRes,
            guideRes,
            roomRes,
            postRes,
          ] = await Promise.allSettled([
            withTimeout(wildPromise, 7000, { data: null, error: new Error('wild_timeout') }),
            withTimeout(noticePromise, 7000, { data: [], error: null }),
            withTimeout(guidePromise, 7000, { data: [], error: null }),
            withTimeout(roomPromise, 7000, { data: [], error: null }),
            withTimeout(postPromise, 7000, { data: [], error: null }),
          ]);

          if (!active) return;
          const wildValue = wildRes.status === 'fulfilled' ? wildRes.value : { data: null, error: wildRes.reason };
          const noticeValue = noticeRes.status === 'fulfilled' ? noticeRes.value : { data: [] };
          const guideValue = guideRes.status === 'fulfilled' ? guideRes.value : { data: [] };
          const roomValue = roomRes.status === 'fulfilled' ? roomRes.value : { data: [] };
          const postValue = postRes.status === 'fulfilled' ? postRes.value : { data: [] };
          const { data: w, error: we } = wildValue;
          const noticeData = noticeValue.data || [];
          const guideData = guideValue.data || [];
          const roomData = roomValue.data || [];
          const postData = postValue.data || [];
          const fallbackGame = ((global.WILDY_GAMES || []).find(g => g.id === wildId)) || null;
          if (we && !fallbackGame) throw we;
          if (!w && !fallbackGame) { setError('존재하지 않는 Wild예요'); setLoading(false); return; }

          setWild(w || {
            id: fallbackGame.id,
            name: fallbackGame.name,
            short_name: fallbackGame.short,
            emoji: fallbackGame.emoji,
            category: fallbackGame.category || fallbackGame.tag,
            member_count: parseFloat(String(fallbackGame.users || '0')) * (String(fallbackGame.users || '').toLowerCase().includes('k') ? 1000 : 1),
            active_now: 0,
            short_description: fallbackGame.downloads || '',
          });
          // setIsFollowing ?쒓굅 ??isFollowing ? followedGames prop ?쇰줈 ?좊룄 (useMemo)

          // 怨듭? ?곗꽑?쒖쐞: admin ?묒꽦 ???곸쐞 3媛?          const noticeArr = (noticeData || []).filter(p => p.author?.is_admin).slice(0, 3);
          if (noticeArr.length === 0 && noticeData?.length > 0) {
            // admin 湲 ?놁쑝硫?type='discussion' 理쒖떊 3媛쒕? ?꾩떆 怨듭?濡?            noticeArr.push(...noticeData.filter(p => p.type === 'discussion').slice(0, 3));
          }
          setNotices(noticeArr);
          setGuides(guideData || []);

          // 梨꾪똿諛?鍮꾩뼱?덉쑝硫?mock?쇰줈 ?쒖뿰 (踰좏? ?④퀎 UX)
          if (roomData && roomData.length > 0) {
            setRooms(roomData);
          } else {
            setRooms(SAMPLE_ROOMS);
          }

          // ?쇰컲 寃뚯떆臾??쇰뱶 ??媛?대뱶/由щ럭?????뱀뀡???대? ?덉쑝???쒖쇅 (以묐났 諛⑹?)
          const exclude = new Set([
            ...(guideData || []).map(g => g.id),
            ...noticeArr.map(n => n.id),
          ]);
          excludeIdsRef.current = exclude;
          const feedPosts = (postData || []).filter(p => !exclude.has(p.id));
          setPosts(feedPosts);
          // 臾댄븳 ?ㅽ겕濡??곹깭 珥덇린????DB?먯꽌 諛쏆? row ??湲곗??쇰줈 ?ㅼ쓬 ?섏씠吏 議댁옱 ?щ? ?먮떒
          postsOffsetRef.current = (postData || []).length;
          setPostsHasMore((postData || []).length >= POSTS_PAGE);

          setLoading(false);
        } catch (e) {
          if (!active) return;
          console.error('[WildDetailScreen] load', e);
          setError('Wild ?뺣낫瑜?遺덈윭?ㅼ? 紐삵뻽?댁슂');
          setLoading(false);
        }
      })();
      return () => { active = false; };
    }, [supabaseClient, wildId, user?.id, roomsRefreshTick]);

    // ??? 而ㅻ??덊떚 ?쇰뱶 ?ㅼ쓬 ?섏씠吏 濡쒕뱶 (#3 臾댄븳 ?ㅽ겕濡? ???
    const loadMorePosts = useCallback(async () => {
      if (!supabaseClient || postsLoadingMore || !postsHasMore) return;
      setPostsLoadingMore(true);
      try {
        const from = postsOffsetRef.current;
        const to = from + POSTS_PAGE - 1;
        const { data, error: e } = await supabaseClient
          .from('posts')
          .select('id,text,image_urls,video_url,star_count,comment_count,created_at,author_id,game_tag,type,author:users!author_id(display_name,username,avatar,is_admin)')
          .eq('game_tag', wildId).eq('is_deleted', false).eq('visibility', 'public')
          .order('created_at', { ascending: false }).range(from, to);
        if (e) throw e;
        const batch = data || [];
        postsOffsetRef.current = from + batch.length;
        setPostsHasMore(batch.length >= POSTS_PAGE);
        setPosts(prev => {
          const seen = new Set(prev.map(p => p.id));
          const fresh = batch.filter(p => !excludeIdsRef.current.has(p.id) && !seen.has(p.id));
          return fresh.length ? [...prev, ...fresh] : prev;
        });
      } catch (err) {
        console.warn('[WildDetailScreen] loadMorePosts', err?.message || err);
        setPostsHasMore(false); // ?ㅽ뙣 ?????쒕룄 ????(?ъ슜??留됱? ?딆쓬)
      } finally {
        setPostsLoadingMore(false);
      }
    }, [supabaseClient, wildId, postsLoadingMore, postsHasMore]);

    // 피드 하단 sentinel이 보이면 다음 페이지를 자동 로드한다.
    useEffect(() => {
      const el = feedSentinelRef.current;
      if (!el || !postsHasMore) return;
      const io = new IntersectionObserver((entries) => {
        if (entries.some(en => en.isIntersecting)) loadMorePosts();
      }, { rootMargin: '400px 0px' });
      io.observe(el);
      return () => io.disconnect();
    }, [postsHasMore, loadMorePosts]);

    // 채팅방을 room_type별로 묶어 보여준다.
    const roomGroups = useMemo(() => {
      const order = ['meetup', 'free', 'social', 'recruit', 'notice', 'private'];
      const buckets = {};
      (rooms || []).forEach(r => {
        const t = ROOM_TYPE_LABEL[r.room_type] ? r.room_type : 'free';
        (buckets[t] = buckets[t] || []).push(r);
      });
      return order
        .filter(t => buckets[t] && buckets[t].length)
        .map(t => ({ type: t, meta: ROOM_TYPE_LABEL[t], rooms: buckets[t] }));
    }, [rooms]);

    if (loading) {
      return (
        <div className="min-h-screen w-full bg-white flex items-center justify-center text-slate-400 text-sm" style={{ maxWidth: 1080, margin: '0 auto' }}>
          濡쒕뵫 以?..
        </div>
      );
    }
    if (error) {
      return (
        <div className="min-h-screen w-full bg-white px-5 pt-10" style={{ maxWidth: 1080, margin: '0 auto' }}>
          <button onClick={onBack} className="mb-4 text-sm text-slate-500">???ㅻ줈</button>
          <div className="rounded-2xl bg-rose-50 px-4 py-3 text-sm text-rose-600">{error}</div>
        </div>
      );
    }

    const title = localize(wild, lang);
    const isUsingSampleRooms = rooms === SAMPLE_ROOMS || (rooms.length > 0 && String(rooms[0].id).startsWith('sample-'));

    // 梨꾪똿諛㈑룻뙆?곕갑 ?뱀뀡 (#2: ?쇱씠釉?梨꾪똿 諛붾줈 ?섎떒, 怨꾩뿴蹂?洹몃９??
    const RoomsSection = (
      <div className="px-5 sm:px-8 lg:px-10 mt-8 lg:mt-10">
        <div className="mb-4 flex items-end justify-between flex-wrap gap-3">
          <div>
            <h2 className="font-display text-xl lg:text-2xl font-black text-wildy-ink flex items-center gap-2">
              <span>?뤇截?/span><span>吏湲??대젮?덈뒗 梨꾪똿諛?쨌 ?뚰떚諛?/span>
            </h2>
            <p className="mt-1 text-[11px] text-slate-500 uppercase tracking-wider font-bold">Live Rooms 쨌 Parties 쨌 Guilds</p>
          </div>
          {user?.id && !isUsingSampleRooms && (
            <button
              onClick={() => setCreateOpen(true)}
              className="rounded-full bg-wildy-ink text-white px-5 py-2.5 text-sm font-bold hover:-translate-y-0.5 transition shadow-ink"
            >
              + ??梨꾪똿諛?留뚮뱾湲?            </button>
          )}
        </div>

        {isUsingSampleRooms ? (
          <div className="rounded-2xl bg-sky-50/60 border-2 border-dashed border-sky-200 px-5 py-12 text-center" style={{ wordBreak: 'keep-all' }}>
            <div className="text-4xl mb-3">?벊</div>
            <p className="font-display text-lg font-black text-wildy-ink mb-2">?꾩쭅 留뚮뱾?댁쭊 梨꾪똿諛⑹씠 ?놁뼱??/p>
            <p className="text-sm text-slate-600 mb-5">泥?踰덉㎏ 諛⑹쓣 留뚮뱾???ㅻⅨ Wilder?ㅼ쓣 紐⑥븘蹂댁꽭??</p>
            {user?.id ? (
              <button
                onClick={() => setCreateOpen(true)}
                className="rounded-full bg-wildy-ink text-white px-6 py-3 text-sm font-bold hover:-translate-y-0.5 transition shadow-ink"
              >
                + 泥?梨꾪똿諛?留뚮뱾湲?              </button>
            ) : (
              <p className="text-xs text-slate-500">濡쒓렇????梨꾪똿諛⑹쓣 留뚮뱾 ???덉뼱??/p>
            )}
          </div>
        ) : (
          <div className="space-y-5">
            {roomGroups.map(grp => (
              <div key={grp.type}>
                <div className="mb-2 flex items-center gap-2">
                  <span className={`rounded-full px-2.5 py-0.5 text-[11px] font-black ${grp.meta.cls}`}>
                    {grp.meta.emoji} {grp.meta.label}
                  </span>
                  <span className="text-[11px] text-slate-400 font-bold">{grp.rooms.length}媛?/span>
                  <span className="h-px flex-1 bg-slate-100"></span>
                </div>
                <div className="grid gap-2 sm:grid-cols-2">
                  {grp.rooms.map(r => (
                    <button
                      key={r.id}
                      onClick={() => handleRoomClick(r)}
                      className="w-full flex items-center gap-3 rounded-2xl border border-slate-100 bg-white px-4 py-3 hover:border-sky-200 hover:shadow-cloud transition text-left"
                    >
                      <span className={`flex h-9 w-9 items-center justify-center rounded-2xl text-lg ${grp.meta.cls}`}>
                        {grp.meta.emoji}
                      </span>
                      <div className="flex-1 min-w-0">
                        <div className="flex items-center gap-2">
                          <span className="font-bold text-sm text-wildy-ink truncate">{r.name}</span>
                          {r.is_private && <span className="text-amber-600 text-xs">?뵏</span>}
                        </div>
                        <div className="text-[11px] text-slate-500 mt-0.5 flex items-center gap-2">
                          <span>{(r.member_count || 0).toLocaleString('ko-KR')}紐?/span>
                          {r.last_message_at && <span>쨌 {relativeTime(r.last_message_at)}</span>}
                        </div>
                      </div>
                      <span className="text-slate-300 text-sm shrink-0">??/span>
                    </button>
                  ))}
                </div>
              </div>
            ))}
            <p className="text-[11px] text-slate-400" style={{ wordBreak: 'keep-all' }}>
              諛⑹뿉 ?낆옣?섎젮硫?濡쒓렇?몄씠 ?꾩슂?댁슂. 湲몃뱶??Wilder?ㅼ씠 吏곸젒 留뚮뱺 ?뚮え?꾩씠?먯슂.
            </p>
          </div>
        )}
      </div>
    );

    return (
      <div className="mx-auto w-full max-w-[1440px] lg:grid lg:grid-cols-[minmax(0,1fr)_300px] lg:gap-6 lg:px-4 lg:py-6">
       <div className="min-h-screen w-full bg-white pb-24">
        {/* ??? Sticky header ??? */}
        <div className="sticky top-0 z-10 bg-white/95 backdrop-blur px-5 py-3 border-b border-slate-100 flex items-center justify-between">
          <button onClick={onBack} className="flex h-9 w-9 items-center justify-center rounded-full hover:bg-slate-100 text-lg">??/button>
          <span className="font-bold text-sm text-wildy-ink truncate px-2">{title}</span>
          <div className="w-9"></div>
        </div>

        {/* ??? Hero (?좊Ц 1硫??? ??? */}
        <div className="px-5 sm:px-8 lg:px-10 pt-8 lg:pt-12 border-b border-slate-900/10 pb-8">
          <div className="flex items-start gap-5 lg:gap-7">
            <div className="flex-shrink-0">
              {wild.icon_url ? (
                <img src={wild.icon_url} alt={title} className="h-24 w-24 lg:h-32 lg:w-32 rounded-2xl object-cover bg-slate-100" onError={(e) => { e.target.style.display = 'none'; }} />
              ) : (
                <div className="h-24 w-24 lg:h-32 lg:w-32 rounded-2xl bg-wildy-cloud flex items-center justify-center text-5xl lg:text-6xl">{wild.emoji || '?렜'}</div>
              )}
            </div>
            <div className="flex-1 min-w-0">
              {wild.category && (
                <span className="mb-2 inline-block text-[11px] font-black uppercase tracking-widest text-sky-700">
                  {wild.category}
                </span>
              )}
              <h1 className="font-display text-3xl sm:text-4xl lg:text-5xl font-black text-wildy-ink leading-[1.05] tracking-tight">
                {title}
              </h1>
              <div className="mt-3 flex items-center gap-3 text-xs lg:text-sm text-slate-500">
                <span>?뫁 硫ㅻ쾭 {(wild.member_count || 0).toLocaleString('ko-KR')}紐?/span>
                {wild.developer && <span className="text-slate-300">쨌</span>}
                {wild.developer && <span>{wild.developer}</span>}
              </div>
            </div>
          </div>

          {wild.short_description && (
            <p className="mt-5 text-base lg:text-lg text-slate-700 leading-relaxed max-w-3xl font-serif" style={{ wordBreak: 'keep-all' }}>
              {wild.short_description}
            </p>
          )}

          <div className="mt-6 flex flex-wrap gap-2">
            {/* onToggle ?꾩엫 ??App.toggleFollow 媛 wild_subscriptions DB +
                followedGames ?꾩뿭 ?곹깭 + ?ъ씠?쒕컮 "??Wild" 紐⑤몢 媛깆떊.
                initialFollowing ? followedGames ?먯꽌 ?좊룄??媛?(?⑥씪 吏꾩떎). */}
            <FollowButton
              supabaseClient={supabaseClient} user={user} wildId={wildId}
              initialFollowing={isFollowing} source="manual" size="lg"
              onToggle={onToggleFollow}
            />
            {onOpenComposer && (
              <button
                onClick={() => onOpenComposer(wildId)}
                className="rounded-full border-2 border-sky-200 bg-white px-5 py-3 text-sm font-bold text-sky-700 hover:bg-sky-50 transition"
              >
                + 寃뚯떆臾?              </button>
            )}
          </div>
        </div>

        {/* ??? ??諛?(寃뚯엫 ?섏씠吏 ?듯빀 #2) ???쇰뱶/怨듭떇/梨꾪똿/硫ㅻ쾭 ??? */}
        <div className="sticky top-12 z-[5] bg-white/95 backdrop-blur border-b border-slate-100">
          <div className="mx-auto max-w-[1100px] px-5 sm:px-8 lg:px-10 flex gap-1 overflow-x-auto">
            {[
              { k: 'feed',     l: '?벐 ?쇰뱶',  c: posts.length + guides.length },
              { k: 'official', l: '?뱼 怨듭떇',  c: notices.length },
              { k: 'chat',     l: '?뮠 梨꾪똿',  c: rooms.filter(r => !String(r.id || '').startsWith('sample-')).length },
              { k: 'members',  l: '?뫁 硫ㅻ쾭',  c: wild.member_count || 0 },
            ].map(t => (
              <button
                key={t.k}
                onClick={() => setTab(t.k)}
                className={`shrink-0 px-4 py-3 text-sm font-bold border-b-2 transition ${tab === t.k ? 'border-wildy-ink text-wildy-ink' : 'border-transparent text-slate-500 hover:text-wildy-ink'}`}
              >
                {t.l} <span className={`ml-1 text-[10px] ${tab === t.k ? 'text-amber-600' : 'text-slate-400'}`}>{t.c}</span>
              </button>
            ))}
          </div>
        </div>

        {/* ??? tab: 梨꾪똿 ???쇱씠釉?梨꾪똿 + 梨꾪똿諛㈑룻뙆?곕갑 ??? */}
        {tab === 'chat' && (
          <>
            <div className="mx-5 sm:mx-8 lg:mx-10 mt-8 lg:mt-10 rounded-3xl bg-gradient-to-br from-wildy-ink to-slate-800 p-6 lg:p-10 text-white shadow-ink relative overflow-hidden">
              <div className="absolute -top-10 -right-10 w-40 h-40 lg:w-60 lg:h-60 bg-sky-500/20 rounded-full blur-3xl pointer-events-none"></div>
              <div className="relative">
                <div className="flex items-center gap-2 mb-3">
                  <span className="rounded-full bg-rose-500 px-2.5 py-1 text-[10px] font-black animate-pulse">??LIVE</span>
                  <span className="text-xs text-white/60 font-bold tracking-wider uppercase">?ㅼ떆媛?諛섏쓳</span>
                </div>
                <h2 className="font-display text-2xl lg:text-3xl font-black mb-3 leading-tight">
                  ?뮠 吏湲?{title}?먯꽌 ?쇱뼱?섎뒗 紐⑤뱺 寃?                </h2>
                <p className="text-sm lg:text-base text-white/80 mb-5 max-w-2xl" style={{ wordBreak: 'keep-all' }}>
                  ?ㅼ떆媛꾩쑝濡??ㅻⅨ Wilder?ㅺ낵 ??뷀븯怨? ??ㅻ? 紐⑥쭛?섍퀬, ?⑥튂 ?좊줎?섏꽭??
                  <span className="block mt-1 text-white/60 text-xs">5媛쒓뎅??AI ?먮룞 踰덉뿭 ??湲濡쒕쾶 Wilder?ㅻ룄 ?④퍡?댁슂.</span>
                </p>
                <button
                  onClick={enterLiveChat}
                  disabled={joiningLive}
                  className="rounded-full bg-white text-wildy-ink px-8 py-3.5 text-base font-black hover:-translate-y-0.5 transition disabled:opacity-60 disabled:cursor-wait shadow-lg"
                >
                  {joiningLive ? '?낆옣 以?..' : '?쇱씠釉?梨꾪똿 ?낆옣 ??}
                </button>
              </div>
            </div>
            {RoomsSection}
          </>
        )}

        {/* ??? tab: 怨듭떇 ??怨듭떇 怨듭?쨌?낅뜲?댄듃 (admin author) ??? */}
        {tab === 'official' && (
          <div className="px-5 sm:px-8 lg:px-10 mt-8 lg:mt-10">
            <div className="mb-4 pb-2 border-b-2 border-wildy-ink/80">
              <h2 className="font-display text-xl lg:text-2xl font-black text-wildy-ink flex items-center gap-2">
                <span>?뱼</span><span>怨듭떇 怨듭? 쨌 ?낅뜲?댄듃</span>
              </h2>
              <p className="mt-1 text-[11px] text-slate-500 uppercase tracking-wider font-bold">Official Notices 쨌 Updates</p>
            </div>
            {notices.length === 0 ? (
              <div className="rounded-2xl bg-amber-50/60 border-2 border-dashed border-amber-200 px-5 py-10 text-center text-sm text-amber-800" style={{ wordBreak: 'keep-all' }}>
                <div className="text-3xl mb-2">?벊</div>
                ?꾩쭅 怨듭떇 怨듭?媛 ?놁뼱??              </div>
            ) : (
              <div className="divide-y divide-slate-100">
                {notices.map((p, i) => {
                  const author = p.author || {};
                  const isMain = i === 0;
                  return (
                    <button
                      key={p.id}
                      onClick={() => onOpenPost && onOpenPost(i, notices)}
                      className="w-full text-left py-5 hover:bg-amber-50/30 transition"
                    >
                      <div className="flex items-center gap-2 mb-2">
                        {author.is_admin && <span className="rounded-full bg-amber-400 text-white text-[10px] font-black px-2 py-0.5">OFFICIAL</span>}
                        <span className="text-xs font-bold text-amber-700">@{author.username || 'wildy'}</span>
                        <span className="text-xs text-amber-600/70">쨌 {relativeTime(p.created_at)}</span>
                      </div>
                      <p className={`text-wildy-ink line-clamp-3 font-serif ${isMain ? 'text-lg lg:text-xl font-bold leading-snug' : 'text-base'}`} style={{ wordBreak: 'keep-all' }}>
                        {(p.text || '').slice(0, 180)}
                      </p>
                    </button>
                  );
                })}
              </div>
            )}
          </div>
        )}

        {/* ??? tab: ?쇰뱶 ??怨듬왂 + 而ㅻ??덊떚 寃뚯떆臾???? */}
        {tab === 'feed' && (
          <div className="px-5 sm:px-8 lg:px-10 mt-8 lg:mt-10">
            {/* 怨듬왂 ?뱀뀡 (?곷떒, ?먮젅?댁뀡) */}
            {guides.length > 0 && (
              <section className="mb-10">
                <div className="mb-4 pb-2 border-b-2 border-emerald-500/60">
                  <h2 className="font-display text-xl lg:text-2xl font-black text-wildy-ink flex items-center gap-2">
                    <span>?뱲</span><span>怨듬왂 쨌 媛?대뱶</span>
                  </h2>
                  <p className="mt-1 text-[11px] text-slate-500 uppercase tracking-wider font-bold">Top Guides</p>
                </div>
                <div className="grid gap-3 md:grid-cols-2 lg:grid-cols-3">
                  {guides.map((p, i) => {
                    const author = p.author || {};
                    return (
                      <button
                        key={p.id}
                        onClick={() => onOpenPost && onOpenPost(i, guides)}
                        className="w-full text-left rounded-2xl border border-slate-100 bg-white p-4 hover:border-emerald-200 hover:shadow-cloud transition"
                      >
                        <div className="flex items-center gap-2 mb-1.5">
                          <span className="rounded-full bg-emerald-100 text-emerald-700 text-[10px] font-black px-2 py-0.5">
                            {p.type === 'guide' ? '?뱲 GUIDE' : p.type === 'tip' ? '?뮕 TIP' : '狩?REVIEW'}
                          </span>
                          <span className="text-[10px] text-slate-500">@{author.username || 'wilder'}</span>
                        </div>
                        <p className="text-sm font-bold text-wildy-ink line-clamp-3 leading-snug" style={{ wordBreak: 'keep-all' }}>
                          {(p.text || '').slice(0, 100)}
                        </p>
                        <div className="mt-2 flex gap-3 text-xs text-slate-500">
                          <span>??{p.star_count || 0}</span>
                          <span>?뮠 {p.comment_count || 0}</span>
                        </div>
                      </button>
                    );
                  })}
                </div>
              </section>
            )}

            {/* 而ㅻ??덊떚 ?쇰뱶 (?섎떒, 臾댄븳 ?ㅽ겕濡? */}
            <div className="mb-4 flex items-end justify-between flex-wrap gap-3">
              <div>
                <h2 className="font-display text-xl lg:text-2xl font-black text-wildy-ink flex items-center gap-2">
                  <span>?뙄</span><span>{title} 而ㅻ??덊떚 ?쇰뱶</span>
                </h2>
                <p className="mt-1 text-[11px] text-slate-500 uppercase tracking-wider font-bold">Community Feed</p>
              </div>
              {user?.id && onOpenComposer && (
                <button
                  onClick={() => onOpenComposer(wildId)}
                  className="rounded-full border-2 border-sky-200 bg-white px-4 py-2 text-sm font-bold text-sky-700 hover:bg-sky-50 transition"
                >
                  + 寃뚯떆臾??묒꽦
                </button>
              )}
            </div>

            {posts.length === 0 ? (
              <div className="rounded-2xl bg-slate-50/60 border-2 border-dashed border-slate-200 px-5 py-10 text-center" style={{ wordBreak: 'keep-all' }}>
                <div className="text-3xl mb-2">?벊</div>
                <p className="text-sm font-bold text-wildy-ink mb-1">?꾩쭅 寃뚯떆臾쇱씠 ?놁뼱??/p>
                <p className="text-xs text-slate-500">泥?寃뚯떆臾쇱쓽 二쇱씤怨듭씠 ?섏뼱蹂댁꽭??</p>
              </div>
            ) : (
              <>
                <div className="grid gap-3 md:grid-cols-2">
                  {posts.map((p, i) => {
                    const author = p.author || {};
                    const firstImage = Array.isArray(p.image_urls) && p.image_urls.length > 0 ? p.image_urls[0] : null;
                    return (
                      <button
                        key={p.id}
                        onClick={() => onOpenPost && onOpenPost(i, posts)}
                        className="text-left rounded-2xl border border-slate-100 bg-white overflow-hidden hover:border-sky-200 hover:shadow-cloud transition"
                      >
                        {firstImage && (
                          <div className="h-32 bg-slate-100 overflow-hidden">
                            <img src={firstImage} alt="" className="h-full w-full object-cover" loading="lazy" onError={(e) => { e.target.style.display = 'none'; }} />
                          </div>
                        )}
                        <div className="p-4">
                          <div className="flex items-center gap-2 mb-1.5">
                            <span className="text-xs font-bold text-wildy-ink">{author.display_name || author.username || 'wilder'}</span>
                            {author.username && <span className="text-[10px] text-slate-400">@{author.username}</span>}
                            <span className="text-[10px] text-slate-400">쨌 {relativeTime(p.created_at)}</span>
                          </div>
                          <p className="text-sm text-slate-700 line-clamp-3 leading-snug" style={{ wordBreak: 'keep-all' }}>
                            {p.text || ''}
                          </p>
                          <div className="mt-3 flex items-center gap-3 text-xs text-slate-500">
                            <span className="flex items-center gap-1"><span className="text-amber-400">??/span> {p.star_count || 0}</span>
                            <span className="flex items-center gap-1">?뮠 {p.comment_count || 0}</span>
                          </div>
                        </div>
                      </button>
                    );
                  })}
                </div>
                {/* #3 臾댄븳 ?ㅽ겕濡??????쇰뱶泥섎읆 ?섎떒???우쑝硫??먮룞?쇰줈 ?ㅼ쓬 ?섏씠吏 濡쒕뱶 */}
                {postsHasMore && (
                  <div ref={feedSentinelRef} className="py-8 text-center text-sm text-slate-400">
                    {postsLoadingMore ? '??遺덈윭?ㅻ뒗 以묅? : '?꾨옒濡??ㅽ겕濡ㅽ븯硫?怨꾩냽 蹂????덉뼱??}
                  </div>
                )}
                {!postsHasMore && posts.length > 0 && (
                  <div className="py-8 text-center text-[11px] text-slate-300">???ш린源뚯?媛 ?꾨??덉슂 ??/div>
                )}
              </>
            )}
          </div>
        )}

        {/* ??? tab: 硫ㅻ쾭 ????移댁슫?몃쭔. ?쒖뿰 mock ? DEMO_MODE/GameHubPage 寃쎈줈 泥섎━.
             ????????????????????????????????????????????????????????????????
             ??P3 (?뺤떇 異쒖떆) 媛?대뱶 ?뚮뜑 ?뱀뀡 ?덇퀬 ??踰좏? ?섎룄??誘몃끂異?
                Founder 寃곗젙 (wildy_guide_wilder_policy_2026_05_15.md):
                쨌 ?먮룞 ?곗젙(rank='guide')留뚯쑝濡?怨듭쟻 吏???몄텧 ??遺꾩웳 由ъ뒪??                  - "議곌굔 ?섏뿀?붾뜲 ??????" ??쓽
                  - Sparkle ?대럭吏??移는룹옄??寃뚯떆臾??? ?좎씤
                  - 寃뚯엫-?쒕룞 遺덉씪移?(LoL 湲 ?놁씠 LoL ?붾줈?곕쭔 ??"LoL 媛?대뱶" ?ㅻ끂異?
                쨌 P3 ?꾩엯 援ъ“: "Sparkle 500 + 寃뚯떆臾?10 = ?좎껌 ?먭꺽" + ?댁쁺 ?뱀씤
                쨌 RPC 怨④꺽? docs/guide_wilder_p3_design_memo.md ??蹂댁〈
                  (P3 ?묒뾽 ??SECURITY DEFINER + 怨듦컻 而щ읆留??몄텧 援ъ“ 洹몃?濡?                   ?ы솢?? ?대? ?꾪꽣留?'rank guide+' ??'?뱀씤??媛?대뱶' 濡?援먯껜)
             ???????????????????????????????????????????????????????????????? */}
        {tab === 'members' && (
          <div className="px-5 sm:px-8 lg:px-10 mt-8 lg:mt-10">
            <div className="mb-4 pb-2 border-b-2 border-sky-500/60">
              <h2 className="font-display text-xl lg:text-2xl font-black text-wildy-ink flex items-center gap-2">
                <span>?뫁</span><span>{title} 硫ㅻ쾭</span>
              </h2>
              <p className="mt-1 text-[11px] text-slate-500 uppercase tracking-wider font-bold">Wilders following this Wild</p>
            </div>
            <div className="rounded-3xl border border-sky-100 bg-white p-8 text-center">
              <div className="text-5xl font-display font-black text-wildy-ink">{(wild.member_count || 0).toLocaleString('ko-KR')}</div>
              <div className="mt-2 text-sm text-slate-500">紐낆씠 {title} Wild 瑜??붾줈??以?/div>
              {isFollowing && (
                <div className="mt-4 inline-flex items-center gap-1.5 rounded-full bg-emerald-50 px-3 py-1.5 text-xs font-bold text-emerald-700">
                  <span>??/span> ?섎룄 ?붾줈??以?                </div>
              )}
              <p className="mt-6 text-[11px] text-slate-400" style={{ wordBreak: 'keep-all' }}>
                媛쒕퀎 硫ㅻ쾭 紐⑸줉? ?꾨씪?대쾭??蹂댄샇瑜??꾪빐 鍮꾧났媛쒖엯?덈떎.<br/>
                梨꾪똿諛⑹뿉 ?낆옣?섎㈃ ?④퍡 ?덈뒗 Wilder瑜?蹂????덉뼱??
              </p>
            </div>
          </div>
        )}

        <div className="px-5 mt-12 mb-4 text-center text-[11px] text-slate-400" style={{ wordBreak: 'keep-all' }}>
          {title}??紐⑤뱺 ?쒕룞? Wildy ?댁쁺?뺤콉???곕씪??
        </div>
       </div>

        {/* ??? ?곗륫 怨듯넻 ?ъ씠?쒕컮 (#4: 濡쒓렇?명븯硫??대뒓 ?섏씠吏????긽 ?놁뿉) ??? */}
        <aside className="hidden lg:block sticky top-24 self-start">
          {global.WildyComponents?.RightSidebar && (
            <global.WildyComponents.RightSidebar
              supabaseClient={supabaseClient}
              user={user}
              lang={lang}
              followedGames={followedGames}
              onOpenWild={(wid) => onNavigate && onNavigate('wild-detail', null, null, { wildId: wid })}
              onToggleFollow={onToggleFollow}
              onNavigate={onNavigate}
            />
          )}
        </aside>

        {/* 梨꾪똿諛??앹꽦 紐⑤떖 */}
        {createOpen && global.WildyComponents?.CreateRoomModal && (
          <global.WildyComponents.CreateRoomModal
            supabaseClient={supabaseClient}
            user={user}
            wildId={wildId}
            wildName={title}
            onClose={() => setCreateOpen(false)}
            onCreated={handleRoomCreated}
          />
        )}
      </div>
    );
  }

  global.WildyComponents = global.WildyComponents || {};
  global.WildyComponents.WildDetailScreen = WildDetailScreen;
  global.WildyComponents.FollowButton = FollowButton;
})(typeof window !== 'undefined' ? window : globalThis);
