/* ============================================================================
 * Wildy — 게시물 상세 풀스크린 (Phase 1B — 하이브리드 흐름)
 * ----------------------------------------------------------------------------
 *   spec: 인스타 그리드 + 게시판 진입
 *     · 풀스크린, 상하 스와이프(모바일) / ↑↓ 키(PC)로 list 내 prev/next
 *     · Wild 뱃지 클릭 → 해당 Wild 피드로 이동
 *     · 본인 게시물이면 ⋮ 메뉴 (편집/삭제)
 *     · 댓글 섹션 (현재는 read-only — Phase 1D에서 작성 입력 추가)
 *     · "이 Wild에서 더 보기 →" 버튼
 *
 *   사용:
 *     <window.WildyComponents.PostDetailScreen
 *        supabaseClient={...}
 *        user={user}                    // 본인 정보 (편집 권한 판정)
 *        posts={postsArray}             // list (이전/다음 네비)
 *        initialIndex={0}
 *        lang="ko"
 *        onClose={() => ...}
 *        onOpenWild={(wildId) => ...}   // Wild 뱃지 클릭
 *        onDeletePost={(postId) => ...} // 삭제 후 부모 갱신용 콜백
 *     />
 *
 *   글로벌 노출:
 *     window.WildyComponents.PostDetailScreen
 * ========================================================================= */
(function (global) {
  'use strict';

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

  function localizeWild(w, lang) {
    if (!w) return '';
    if (lang === 'en' && w.title_en) return w.title_en;
    if (lang === 'ja' && w.title_ja) return w.title_ja;
    if (lang === 'zh' && w.title_zh) return w.title_zh;
    if (lang === 'id' && w.title_id) return w.title_id;
    return w.short_name || w.name || w.id;
  }
  // @멘션 렌더 — 'hello @gamer123 nice' → 'hello' + <a>@gamer123</a> + 'nice'
  function renderMentions(text) {
    if (!text) return text;
    const parts = String(text).split(/(@[A-Za-z0-9_]{2,30})/g);
    return parts.map((p, i) => {
      if (p.startsWith('@') && p.length > 1) {
        return <span key={i} className="font-bold text-sky-600">{p}</span>;
      }
      return p;
    });
  }

  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 PostDetailScreen({
    supabaseClient, user, posts, initialIndex = 0, lang = 'ko',
    onClose, onOpenWild, onDeletePost, onStartDM, onSparkleChanged,
  }) {
    const [index, setIndex] = useState(Math.max(0, Math.min(initialIndex, (posts || []).length - 1)));
    const [comments, setComments] = useState([]);
    const [commentsLoading, setCommentsLoading] = useState(false);
    const [menuOpen, setMenuOpen] = useState(false);
    const [busy, setBusy] = useState(false);
    const [commentDraft, setCommentDraft] = useState('');
    const [commentSending, setCommentSending] = useState(false);
    const [commentError, setCommentError] = useState('');
    const scrollRef = useRef(null);
    const commentInputRef = useRef(null);

    const total = (posts || []).length;
    const post = (posts || [])[index];
    const isOwn = Boolean(user?.id && post && post.author_id === user.id);

    // ────────── 키보드 nav (PC) ──────────
    useEffect(() => {
      const handler = (e) => {
        if (e.target && /^(INPUT|TEXTAREA|SELECT)$/.test(e.target.tagName)) return;
        if (e.key === 'ArrowUp' || e.key === 'k' || e.key === 'K') {
          e.preventDefault();
          setIndex(i => Math.max(0, i - 1));
        } else if (e.key === 'ArrowDown' || e.key === 'j' || e.key === 'J') {
          e.preventDefault();
          setIndex(i => Math.min(total - 1, i + 1));
        } else if (e.key === 'Escape') {
          onClose && onClose();
        }
      };
      window.addEventListener('keydown', handler);
      return () => window.removeEventListener('keydown', handler);
    }, [total, onClose]);

    // ────────── 모바일 스와이프 (touch) ──────────
    const touchStartRef = useRef(null);
    const onTouchStart = (e) => { touchStartRef.current = { y: e.touches[0].clientY, t: Date.now() }; };
    const onTouchEnd = (e) => {
      if (!touchStartRef.current) return;
      const dy = e.changedTouches[0].clientY - touchStartRef.current.y;
      const dt = Date.now() - touchStartRef.current.t;
      touchStartRef.current = null;
      // 스크롤이 끝에 닿았을 때만 prev/next 발동 (본문 스크롤과 분리)
      const el = scrollRef.current;
      if (!el) return;
      const atTop = el.scrollTop <= 0;
      const atBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 4;
      if (Math.abs(dy) < 50 || dt > 500) return;
      if (dy > 60 && atTop) setIndex(i => Math.max(0, i - 1));
      else if (dy < -60 && atBottom) setIndex(i => Math.min(total - 1, i + 1));
    };

    // ────────── Star 상태 ──────────
    const [starred, setStarred] = useState(false);
    const [starCount, setStarCount] = useState(post?.star_count || 0);
    const [starBusy, setStarBusy] = useState(false);

    useEffect(() => {
      setStarCount(post?.star_count || 0);
      if (!post?.id || !user?.id || !supabaseClient) { setStarred(false); return; }
      let active = true;
      (async () => {
        try {
          const { data } = await supabaseClient
            .from('stars')
            .select('id')
            .eq('user_id', user.id)
            .eq('target_type', 'post')
            .eq('target_id', post.id)
            .maybeSingle();
          if (active) setStarred(Boolean(data));
        } catch {}
      })();
      return () => { active = false; };
    }, [post?.id, user?.id, supabaseClient, post?.star_count]);

    const toggleStar = async () => {
      if (starBusy || !user?.id || !post?.id || !supabaseClient) return;
      setStarBusy(true);
      const was = starred;
      // optimistic
      setStarred(!was);
      setStarCount(c => Math.max(0, c + (was ? -1 : 1)));
      try {
        if (was) {
          const { error } = await supabaseClient
            .from('stars')
            .delete()
            .eq('user_id', user.id)
            .eq('target_type', 'post')
            .eq('target_id', post.id);
          if (error) throw error;
        } else {
          const { error } = await supabaseClient
            .from('stars')
            .insert({ user_id: user.id, target_type: 'post', target_id: post.id });
          if (error && !String(error.message || '').includes('duplicate')) throw error;
        }
        const nextCount = Math.max(0, (post.star_count || 0) + (was ? -1 : 1));
        post.star_count = nextCount;
        post.likes = nextCount;
        onSparkleChanged && onSparkleChanged({ postId: post.id, starred: !was, starCount: nextCount });
      } catch (e) {
        console.error('[PostDetail] toggleStar', e);
        // rollback
        setStarred(was);
        setStarCount(c => Math.max(0, c + (was ? 1 : -1)));
      } finally {
        setStarBusy(false);
      }
    };

    // ────────── index 바뀔 때 스크롤 리셋 + 댓글 로드 ──────────
    useEffect(() => {
      if (scrollRef.current) scrollRef.current.scrollTop = 0;
      setMenuOpen(false);
      if (!post?.id) { setComments([]); return; }

      if (!supabaseClient) { setComments([]); return; }
      let active = true;
      setCommentsLoading(true);
      (async () => {
        try {
          let { data, error: cErr } = await supabaseClient
            .from('comments')
            .select('id,author_id,text,language,star_count,created_at,author:users!author_id(display_name,username,avatar)')
            .eq('post_id', post.id)
            .eq('is_deleted', false)
            .order('created_at', { ascending: true })
            .limit(50);
          if (cErr) {
            console.warn('[PostDetail] comments join failed, plain select:', cErr.message);
            const r = await supabaseClient
              .from('comments')
              .select('id,author_id,text,star_count,created_at')
              .eq('post_id', post.id)
              .eq('is_deleted', false)
              .order('created_at', { ascending: true })
              .limit(50);
            data = r.data;
          }
          if (active) setComments(data || []);
        } catch (e) {
          console.warn('[PostDetail] comments fetch failed', e.message);
          if (active) setComments([]);
        } finally {
          if (active) setCommentsLoading(false);
        }
      })();
      return () => { active = false; };
    }, [post?.id, supabaseClient]);

    const goPrev = () => setIndex(i => Math.max(0, i - 1));
    const goNext = () => setIndex(i => Math.min(total - 1, i + 1));

    const handleDelete = async () => {
      if (!post?.id) return;
      if (!confirm('이 게시물을 삭제할까요? 되돌릴 수 없어요.')) return;
      setBusy(true);
      try {
        if (supabaseClient) {
          const { error } = await supabaseClient
            .from('posts')
            .update({ is_deleted: true })
            .eq('id', post.id)
            .eq('author_id', user.id);
          if (error) throw error;
        }
        onDeletePost && onDeletePost(post.id);
        // 다음 게시물 또는 닫기
        if (total > 1) {
          setIndex(i => Math.min(i, total - 2));
        } else {
          onClose && onClose();
        }
      } catch (e) {
        alert('삭제 실패: ' + (e?.message || ''));
      } finally {
        setBusy(false);
        setMenuOpen(false);
      }
    };

    // ────────── 댓글 작성 ──────────
    const sendComment = async () => {
      const v = (commentDraft || '').trim();
      if (!v || commentSending || !post?.id) return;
      if (!supabaseClient || !user?.id) {
        setCommentError('로그인 후 댓글을 작성할 수 있어요');
        return;
      }
      setCommentSending(true);
      setCommentError('');
      try {
        // AI 모더레이션 이중 안전 (한국어 키워드 + OpenAI)
        try {
          const modHeaders = { 'Content-Type': 'application/json' };
          if (supabaseClient) {
            try {
              const { data } = await supabaseClient.auth.getSession();
              const token = data?.session?.access_token;
              if (token) modHeaders.Authorization = `Bearer ${token}`;
            } catch {}
          }
          const mr = await fetch('/api/moderate', {
            method: 'POST',
            headers: modHeaders,
            body: JSON.stringify({
              text: v.slice(0, 2000),
              context_type: 'comment',
              context_id: post.id,
            }),
          });
          if (mr.ok) {
            const md = await mr.json();
            if (md && md.ok === false && md.flagged) {
              setCommentError(md.reason || '부적절한 표현이 포함되어 있어요. 다시 작성해주세요.');
              setCommentSending(false);
              return;
            }
          }
        } catch (modErr) {
          // 모더레이션 장애 = 통과
        }

        const { data, error } = await supabaseClient
          .from('comments')
          .insert({
            post_id: post.id,
            author_id: user.id,
            text: v.slice(0, 2000),
            language: lang || 'ko',
          })
          .select('id,post_id,author_id,text,language,star_count,created_at')
          .single();
        if (error) throw error;
        // 사용자 정보 조인 시도 (실패해도 기본값으로 표시)
        let author = { display_name: user.display_name || user.nickname || 'Wilder', username: user.username };
        try {
          const { data: userData } = await supabaseClient
            .from('users').select('display_name,username,avatar').eq('id', user.id).maybeSingle();
          if (userData) author = userData;
        } catch {}
        setComments(prev => [...prev, { ...data, author }]);
        setCommentDraft('');
      } catch (e) {
        console.error('[PostDetail] sendComment failed', e);
        const helpers = global.WildyLib?.SupabaseHelpers;
        setCommentError(helpers?.translateAuthError ? helpers.translateAuthError(e) : (e?.message || '댓글 작성 실패'));
      } finally {
        setCommentSending(false);
      }
    };

    if (!post) {
      return (
        <div className="fixed inset-0 z-[140] flex items-center justify-center bg-white" style={{ maxWidth: 480, margin: '0 auto' }}>
          <div className="text-center">
            <p className="text-slate-500 text-sm">게시물이 없어요</p>
            <button onClick={onClose} className="mt-4 rounded-full bg-wildy-ink px-6 py-2 text-sm font-bold text-white">닫기</button>
          </div>
        </div>
      );
    }

    // author 정보 — post에 author/users 임베디드 또는 본인이면 user prop fallback
    const author = post.author || post.users || (isOwn && user ? { display_name: user.display_name || user.nickname || 'Wilder', username: user.username || 'wilder' } : {});
    const wild = post.wild || post.wilds || null;
    const hasImages = Array.isArray(post.image_urls) && post.image_urls.length > 0;

    return (
      <div className="fixed inset-0 z-[140] bg-white flex flex-col" style={{ maxWidth: 480, margin: '0 auto', boxShadow: '0 0 0 1px rgba(0,0,0,0.04)' }}>
        {/* ─── Sticky header ─── */}
        <div className="flex items-center justify-between border-b border-slate-100 px-4 py-3 bg-white">
          <button onClick={onClose} className="flex h-9 w-9 items-center justify-center rounded-full hover:bg-slate-100 text-lg" aria-label="닫기">←</button>
          <div className="flex items-center gap-2 text-xs text-slate-500">
            <span>{index + 1} / {total}</span>
          </div>
          <div className="relative">
            {isOwn ? (
              <>
                <button onClick={() => setMenuOpen(o => !o)} className="flex h-9 w-9 items-center justify-center rounded-full hover:bg-slate-100" aria-label="메뉴">⋮</button>
                {menuOpen && (
                  <div className="absolute right-0 top-10 z-10 w-32 rounded-2xl border border-slate-100 bg-white shadow-cloud overflow-hidden">
                    <button onClick={() => { setMenuOpen(false); alert('편집 기능은 Phase 1C에서 활성화될 예정이에요'); }} className="block w-full px-4 py-2.5 text-left text-sm hover:bg-slate-50">✏️ 편집</button>
                    <button onClick={handleDelete} disabled={busy} className="block w-full px-4 py-2.5 text-left text-sm text-rose-600 hover:bg-rose-50 disabled:opacity-50">🗑 삭제</button>
                  </div>
                )}
              </>
            ) : (
              <div className="w-9 h-9"></div>
            )}
          </div>
        </div>

        {/* ─── Scrollable body ─── */}
        <div
          ref={scrollRef}
          onTouchStart={onTouchStart}
          onTouchEnd={onTouchEnd}
          className="flex-1 overflow-y-auto"
        >
          {/* 작성자 + 메시지 버튼 + Wild 뱃지 */}
          <div className="flex items-center justify-between gap-3 px-4 py-3 border-b border-slate-50">
            <div className="flex items-center gap-2.5 min-w-0">
              <div className="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full bg-wildy-cloud text-lg">
                👤
              </div>
              <div className="min-w-0">
                <div className="font-bold text-sm text-wildy-ink truncate">{author.display_name || author.username || 'Wilder'}</div>
                <div className="text-xs text-slate-500 truncate">@{author.username || 'wilder'} · {relativeTime(post.created_at)}</div>
              </div>
            </div>
            {/* "💬 메시지" — 본인 게시물 아니고, 로그인 + onStartDM 콜백 있을 때만 */}
            {!isOwn && user?.id && onStartDM && post.author_id && (
              <button
                onClick={() => onStartDM(post.author_id, author.display_name || author.username || 'Wilder')}
                className="flex-shrink-0 rounded-full border-2 border-sky-200 bg-white px-3 py-1.5 text-xs font-bold text-sky-700 hover:bg-sky-50 transition"
                title="DM 시작하기"
              >
                💬 메시지
              </button>
            )}
            {wild && (
              <button
                onClick={() => onOpenWild && onOpenWild(wild.id || post.game_tag)}
                className="flex-shrink-0 rounded-full bg-sky-50 px-2.5 py-1 text-xs font-bold text-sky-700 hover:bg-sky-100 transition"
              >
                {wild.emoji ? `${wild.emoji} ` : ''}{localizeWild(wild, lang)}
              </button>
            )}
            {!wild && post.game_tag && (
              <button
                onClick={() => onOpenWild && onOpenWild(post.game_tag)}
                className="flex-shrink-0 rounded-full bg-sky-50 px-2.5 py-1 text-xs font-bold text-sky-700 hover:bg-sky-100"
              >
                #{post.game_tag}
              </button>
            )}
          </div>

          {/* 이미지 (1-3) */}
          {hasImages && (
            <div className="bg-slate-50">
              {post.image_urls.map((url, i) => (
                <img key={i} src={url} alt="" className="w-full" loading="lazy" onError={(e) => { e.target.style.display = 'none'; }} />
              ))}
            </div>
          )}

          {/* 본문 */}
          {post.text && (
            <div className="px-4 py-4 text-[15px] leading-relaxed text-slate-800 whitespace-pre-wrap" style={{ wordBreak: 'keep-all' }}>
              {post.text}
            </div>
          )}

          {/* 액션 바 (star/comment) — Phase 1A 게이트 적용은 부모에서 wrap */}
          <div className="flex items-center gap-4 px-4 py-3 border-t border-slate-100 text-sm">
            <button
              onClick={toggleStar}
              disabled={starBusy || !user?.id}
              className={`flex items-center gap-1.5 transition disabled:opacity-50 ${starred ? 'text-amber-400' : 'text-slate-700 hover:text-amber-400'}`}
              aria-label={starred ? '✦ Sparkle 취소' : '✦ Sparkle 주기'}
              title={user?.id ? (starred ? '✦ 취소' : '✦ Sparkle 주기') : '로그인 후 Sparkle을 줄 수 있어요'}
            >
              <span className={starred ? '' : 'opacity-40'}>✦</span>
              <span className="font-bold">{starCount}</span>
            </button>
            <button
              onClick={() => commentInputRef.current?.focus()}
              className="flex items-center gap-1.5 text-slate-700 hover:text-sky-600 transition"
              aria-label="댓글 입력으로 이동"
            >
              <span>💬</span><span className="font-bold">{comments.length || post.comment_count || 0}</span>
            </button>
            <div className="flex-1"></div>
            <button className="text-slate-400 hover:text-slate-700" aria-label="공유">↗</button>
          </div>

          {/* "이 Wild에서 더 보기" */}
          {(wild || post.game_tag) && (
            <div className="px-4 py-3 border-t border-slate-100">
              <button
                onClick={() => onOpenWild && onOpenWild((wild && wild.id) || post.game_tag)}
                className="w-full rounded-2xl border-2 border-sky-100 bg-white py-3 text-sm font-bold text-sky-700 hover:bg-sky-50 transition"
              >
                {wild ? `${localizeWild(wild, lang)}에서 더 보기 →` : '이 Wild에서 더 보기 →'}
              </button>
            </div>
          )}

          {/* 댓글 섹션 */}
          <div className="border-t border-slate-100 px-4 py-4">
            <h3 className="mb-3 text-sm font-bold text-wildy-ink">댓글 {comments.length || 0}</h3>
            {commentsLoading && <div className="py-4 text-center text-xs text-slate-400">로딩 중...</div>}
            {!commentsLoading && comments.length === 0 && (
              <div className="py-6 text-center text-xs text-slate-400">아직 댓글이 없어요</div>
            )}
            <div className="space-y-3">
              {comments.map(c => {
                const cu = c.author || c.users || {};
                const handle = cu.username || cu.display_name || 'wilder';
                return (
                  <div key={c.id} className="group flex gap-2.5">
                    <div className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full bg-wildy-cloud text-sm">👤</div>
                    <div className="flex-1 min-w-0">
                      <div className="flex items-baseline gap-2">
                        <span className="text-xs font-bold text-wildy-ink">{cu.display_name || cu.username || 'wilder'}</span>
                        <span className="text-[10px] text-slate-400">{relativeTime(c.created_at)}</span>
                      </div>
                      <div className="mt-0.5 text-sm text-slate-700" style={{ wordBreak: 'keep-all' }}>{renderMentions(c.text)}</div>
                      {user?.id && user.id !== c.author_id && (
                        <button
                          onClick={() => {
                            setCommentDraft(prev => {
                              const mention = `@${handle} `;
                              if (prev.startsWith(mention)) return prev;
                              return mention + prev;
                            });
                            setTimeout(() => commentInputRef.current?.focus(), 0);
                          }}
                          className="mt-1 text-[10px] text-sky-500 hover:underline opacity-0 group-hover:opacity-100 transition"
                        >
                          ↳ 답글
                        </button>
                      )}
                    </div>
                  </div>
                );
              })}
            </div>
            {/* 댓글 입력 */}
            {user?.id && (
              <div className="mt-4 border-t border-slate-100 pt-3">
                {commentError && (
                  <div className="mb-2 rounded-xl bg-rose-50 px-3 py-2 text-xs text-rose-600">{commentError}</div>
                )}
                <div className="flex items-end gap-2">
                  <textarea
                    ref={commentInputRef}
                    value={commentDraft}
                    onChange={(e) => setCommentDraft(e.target.value)}
                    onKeyDown={(e) => {
                      if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
                        e.preventDefault();
                        sendComment();
                      }
                    }}
                    rows={1}
                    maxLength={2000}
                    placeholder="댓글을 남겨보세요... (Ctrl/Cmd + Enter 전송)"
                    className="flex-1 resize-none rounded-2xl border-2 border-slate-100 px-3 py-2 text-sm outline-none focus:border-sky-300 max-h-32"
                    style={{ minHeight: '36px' }}
                  />
                  <button
                    onClick={sendComment}
                    disabled={commentSending || !commentDraft.trim()}
                    className="rounded-full bg-wildy-ink px-4 py-2 text-xs font-bold text-white disabled:bg-slate-300 hover:-translate-y-0.5 transition"
                  >
                    {commentSending ? '...' : '게시'}
                  </button>
                </div>
              </div>
            )}
            {!user?.id && (
              <p className="mt-4 text-center text-[11px] text-slate-400">댓글 작성은 로그인 후 가능해요</p>
            )}
          </div>

          {/* 아래 nav 힌트 */}
          <div className="pb-8 pt-4 text-center text-[11px] text-slate-400">
            {index < total - 1 ? '↓ 위로 스와이프 또는 ↓ 키로 다음 게시물' : '마지막 게시물이에요'}
          </div>
        </div>

        {/* ─── 측면 nav 버튼 (PC) ─── */}
        <div className="hidden lg:flex absolute left-[-60px] top-1/2 -translate-y-1/2 flex-col gap-2">
          <button onClick={goPrev} disabled={index === 0} className="flex h-10 w-10 items-center justify-center rounded-full bg-white border border-slate-200 shadow-cloud disabled:opacity-30">↑</button>
          <button onClick={goNext} disabled={index >= total - 1} className="flex h-10 w-10 items-center justify-center rounded-full bg-white border border-slate-200 shadow-cloud disabled:opacity-30">↓</button>
        </div>
      </div>
    );
  }

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