<script setup>
import { onMounted, ref, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { boardApi } from '@/api/boardApi'
import { useAuthStore } from '@/stores/auth'
import { useDialog } from '@/composables/dialog'
import { formatRelative } from '@/utils/datetime'
import MarkdownViewer from '@/components/editor/MarkdownViewer.vue'
import MarkdownEditor from '@/components/editor/MarkdownEditor.vue'
import IconBtn from '@/components/ui/IconBtn.vue'
import UserAvatar from '@/components/UserAvatar.vue'
import { DEFAULT_BOARD } from '@/constants/boards'

const route = useRoute()
const router = useRouter()
const auth = useAuthStore()
const dialog = useDialog()

const postId = route.params.id
// 게시판(카테고리): URL 우선, 없으면 글의 category, 그래도 없으면 기본
const category = computed(() => route.params.category || post.value?.category || DEFAULT_BOARD)
const post = ref(null)
const loading = ref(false)
const error = ref(null)
const commentText = ref('')
const submitting = ref(false)

const isAdmin = computed(() => auth.user?.role === 'ADMIN')
// 비관리자에게 제한된 글 (본문/댓글 숨김)
const restricted = computed(() => post.value?.blocked && !isAdmin.value)

const canModifyPost = computed(() => {
  if (!post.value || !auth.user) return false
  return auth.user.id === post.value.authorId || isAdmin.value
})

function canModifyComment(c) {
  if (!auth.user) return false
  return auth.user.id === c.authorId || isAdmin.value
}

// 본인 글/댓글 여부 (추천/비추천 차단용)
const isMyPost = computed(() => !!post.value && auth.user?.id === post.value.authorId)
function isMyComment(c) {
  return auth.user?.id === c.authorId
}
// 본문 작성자가 단 댓글인지 (작성자 뱃지)
function isAuthorComment(c) {
  return !!post.value && c.authorId === post.value.authorId
}
// 비추천 20개 이상 블라인드 + 펼치기 상태
const BLIND_DOWN = 20
function isBlinded(item) {
  return (item?.downCount || 0) >= BLIND_DOWN
}
const postRevealed = ref(false)
const revealedComments = ref({})
function toggleReveal(c) {
  revealedComments.value[c.id] = !revealedComments.value[c.id]
}

async function load() {
  loading.value = true
  error.value = null
  try {
    post.value = await boardApi.get(postId)
  } catch (e) {
    error.value = e.response?.data?.message || '게시글을 불러오지 못했습니다.'
  } finally {
    loading.value = false
  }
}

async function removePost() {
  if (!(await dialog.confirm('이 게시글을 삭제하시겠습니까?', { title: '게시글 삭제', danger: true }))) return
  try {
    await boardApi.remove(postId)
    router.replace({ path: `/board/${category.value}`, query: route.query })
  } catch (e) {
    alert(e.response?.data?.message || '삭제에 실패했습니다.')
  }
}

async function blockPost() {
  const reason = await dialog.prompt('열람 제한 사유 (선택):', { title: '열람 제한', placeholder: '사유(선택)' })
  if (reason === null) return
  try {
    await boardApi.block(postId, reason)
    await load()
  } catch (e) {
    alert(e.response?.data?.message || '처리에 실패했습니다.')
  }
}

async function unblockPost() {
  try {
    await boardApi.unblock(postId)
    await load()
  } catch (e) {
    alert(e.response?.data?.message || '처리에 실패했습니다.')
  }
}

async function addComment() {
  const content = commentText.value.trim()
  if (!content) return
  submitting.value = true
  try {
    const c = await boardApi.addComment(postId, content)
    post.value.comments.push(c)
    commentText.value = ''
  } catch (e) {
    alert(e.response?.data?.message || '댓글 등록에 실패했습니다.')
  } finally {
    submitting.value = false
  }
}

async function removeComment(c) {
  if (!(await dialog.confirm('댓글을 삭제하시겠습니까?', { title: '댓글 삭제', danger: true }))) return
  try {
    await boardApi.removeComment(c.id)
    post.value.comments = post.value.comments.filter((x) => x.id !== c.id)
  } catch (e) {
    alert(e.response?.data?.message || '삭제에 실패했습니다.')
  }
}

// ===== 신고 =====
async function reportPost() {
  if (!(await dialog.confirm('이 게시글을 신고하시겠어요?\n신고가 누적되면 자동으로 블라인드 처리됩니다.', { title: '게시글 신고', danger: true }))) return
  try {
    await boardApi.reportPost(postId)
    await dialog.alert('신고가 접수되었습니다.')
    await load()
  } catch (e) {
    alert(e.response?.data?.message || '신고에 실패했습니다.')
  }
}
async function reportComment(c) {
  if (!(await dialog.confirm('이 댓글을 신고하시겠어요?\n신고가 누적되면 자동으로 블라인드 처리됩니다.', { title: '댓글 신고', danger: true }))) return
  try {
    await boardApi.reportComment(c.id)
    await dialog.alert('신고가 접수되었습니다.')
    await refreshComments()
  } catch (e) {
    alert(e.response?.data?.message || '신고에 실패했습니다.')
  }
}
async function unblockComment(c) {
  try {
    await boardApi.unblockComment(c.id)
    await refreshComments()
  } catch (e) {
    alert(e.response?.data?.message || '해제에 실패했습니다.')
  }
}

// 댓글 목록만 새로고침 (다른 사람이 단 댓글·추천 반영)
const refreshingComments = ref(false)
async function refreshComments() {
  if (refreshingComments.value) return
  refreshingComments.value = true
  try {
    const fresh = await boardApi.get(postId)
    post.value.comments = fresh.comments
  } catch (e) {
    alert(e.response?.data?.message || '댓글을 새로고침하지 못했습니다.')
  } finally {
    refreshingComments.value = false
  }
}

// ===== 추천/비추천 =====
const voting = ref(false)
async function votePost(type) {
  if (voting.value) return
  voting.value = true
  try {
    const res = await boardApi.votePost(postId, type)
    post.value.upCount = res.upCount
    post.value.downCount = res.downCount
    post.value.myVote = res.myVote
    // 추천 변동 → 추천자 목록 갱신
    post.value.recommenders = await boardApi.recommenders(postId)
  } catch (e) {
    alert(e.response?.data?.message || '처리에 실패했습니다.')
  } finally {
    voting.value = false
  }
}

async function voteComment(c, type) {
  try {
    const res = await boardApi.voteComment(c.id, type)
    c.upCount = res.upCount
    c.downCount = res.downCount
    c.myVote = res.myVote
  } catch (e) {
    alert(e.response?.data?.message || '처리에 실패했습니다.')
  }
}

// ===== 추천자 목록 =====
const recommenders = computed(() => post.value?.recommenders || [])
const previewRecommenders = computed(() => recommenders.value.slice(0, 10))
const extraRecommenders = computed(() => Math.max(0, (post.value?.upCount || 0) - 10))
const showRecommenders = ref(false)

onMounted(load)
</script>

<template>
  <section class="detail">
    <p v-if="error" class="msg error">{{ error }}</p>
    <p v-if="loading" class="msg">불러오는 중...</p>

    <article v-if="post">
      <header class="post-head">
        <h1><span v-if="post.notice" class="notice-badge">공지</span>{{ post.title }}</h1>
        <div class="meta">
          <UserAvatar
            :name="post.authorName"
            :google-picture="post.authorGooglePicture"
            :profile-image="post.authorProfileImage"
            :size="16"
          />
          <span class="meta-author">{{ post.authorName }}</span>
          <span>· {{ formatRelative(post.createdAt) }}</span>
          <span>· 조회 {{ post.viewCount }}</span>
          <span>· 추천 {{ post.upCount || 0 }}</span>
        </div>
      </header>

      <!-- 관리자에게: 제한 상태 배너 -->
      <div v-if="post.blocked && isAdmin" class="admin-banner">
        🚫 열람 제한된 글입니다 (관리자만 열람)
        <span v-if="post.blockReason">— 사유: {{ post.blockReason }}</span>
      </div>

      <!-- 비관리자 제한 메시지 -->
      <div v-if="restricted" class="restricted">
        🚫 관리자에 의해 열람이 제한된 게시글입니다.
      </div>

      <!-- 비추천 많은 글 블라인드 (작성자·관리자는 정상 표시) -->
      <div v-else-if="isBlinded(post) && !isMyPost && !isAdmin && !postRevealed" class="blinded">
        🙈 비추천이 많아 블라인드 처리된 게시글입니다.
        <button type="button" class="reveal-btn" @click="postRevealed = true">그래도 보기</button>
      </div>

      <MarkdownViewer v-else :content="post.content" class="content" />

      <!-- 추천 / 비추천 (본인 글은 비활성) -->
      <div v-if="!restricted" class="vote-bar">
        <button
          type="button" class="vote-btn up" :class="{ active: post.myVote === 'UP' }"
          :disabled="voting || isMyPost"
          :title="isMyPost ? '본인 글은 추천할 수 없습니다' : ''"
          @click="votePost('UP')"
        >👍 추천 <b>{{ post.upCount || 0 }}</b></button>
        <button
          type="button" class="vote-btn down" :class="{ active: post.myVote === 'DOWN' }"
          :disabled="voting || isMyPost"
          :title="isMyPost ? '본인 글은 비추천할 수 없습니다' : ''"
          @click="votePost('DOWN')"
        >👎 비추천 <b>{{ post.downCount || 0 }}</b></button>
      </div>

      <!-- 추천자 (아바타 최대 10개 + 초과 안내, 클릭 시 하단에 전체 목록 펼침) -->
      <div v-if="!restricted && post.upCount" class="recommenders-wrap">
        <button type="button" class="recommenders" @click="showRecommenders = !showRecommenders">
          <span class="rec-avatars">
            <UserAvatar
              v-for="r in previewRecommenders"
              :key="r.memberId"
              :name="r.name"
              :google-picture="r.googlePicture"
              :profile-image="r.profileImage"
              :size="16"
              class="rec-avatar"
            />
          </span>
          <span class="rec-label">
            <template v-if="extraRecommenders > 0">+{{ extraRecommenders }}명이 추천했습니다</template>
            <template v-else>{{ post.upCount }}명이 추천했습니다</template>
          </span>
          <span class="rec-toggle">{{ showRecommenders ? '▲' : '▼' }}</span>
        </button>
        <ul v-if="showRecommenders" class="rec-inline-list">
          <li v-for="r in recommenders" :key="r.memberId">
            <UserAvatar
              :name="r.name"
              :google-picture="r.googlePicture"
              :profile-image="r.profileImage"
              :size="16"
            />
            <span class="rec-name">{{ r.name }}</span>
          </li>
        </ul>
      </div>

      <!-- 태그 (본문 아래) -->
      <div v-if="!restricted && post.tags?.length" class="tags">
        <span v-for="t in post.tags" :key="t" class="tag">{{ t }}</span>
      </div>

      <div class="actions">
        <IconBtn icon="list" title="목록" @click="router.push({ path: `/board/${category}`, query: route.query })" />
        <div class="right-actions">
          <!-- 신고 (작성자·관리자 외) -->
          <button
            v-if="!isAdmin && !restricted && auth.user && post.authorId !== auth.user.id"
            type="button" class="report-btn" @click="reportPost"
          >🚩 신고</button>
          <!-- 관리자 제한/해제 -->
          <button v-if="isAdmin && !post.blocked" type="button" class="warn" @click="blockPost">열람 제한</button>
          <button v-if="isAdmin && post.blocked" type="button" class="warn" @click="unblockPost">제한 해제</button>
          <!-- 작성자/관리자 수정·삭제 -->
          <template v-if="canModifyPost && !restricted">
            <IconBtn v-if="!post.blocked" icon="edit" title="수정" @click="router.push(`/board/${category}/${post.id}/edit`)" />
            <IconBtn icon="trash" title="삭제" variant="danger" @click="removePost" />
          </template>
        </div>
      </div>

      <!-- 댓글 (제한 글은 비관리자에게 숨김, 댓글 작성은 제한 글에서 불가) -->
      <section v-if="!restricted" class="comments">
        <h2>댓글 {{ post.comments.length }}</h2>

        <ul class="comment-list">
          <li v-for="c in post.comments" :key="c.id" class="comment" :class="{ 'hot-comment': c.hot }">
            <div class="comment-head">
              <UserAvatar
                :name="c.authorName"
                :google-picture="c.authorGooglePicture"
                :profile-image="c.authorProfileImage"
                :size="16"
              />
              <strong>{{ c.authorName }}</strong>
              <span v-if="isAuthorComment(c)" class="author-badge">작성자</span>
              <span v-if="c.hot" class="hot-badge">🔥 인기</span>
              <span v-if="c.blocked && isAdmin" class="report-badge">🚩 신고 블라인드</span>
              <span class="comment-date">{{ formatRelative(c.createdAt) }}</span>
              <span v-if="canModifyComment(c)" class="comment-del">
                <IconBtn icon="trash" title="댓글 삭제" variant="danger" size="sm" @click="removeComment(c)" />
              </span>
            </div>
            <!-- 신고 누적 블라인드 (관리자만 본문 열람, 그 외엔 가림) -->
            <div v-if="c.blocked && !isAdmin" class="blinded comment-blinded">
              🚩 신고 누적으로 블라인드된 댓글입니다.
            </div>
            <!-- 비추천 많은 댓글 블라인드 (작성자·관리자는 정상) -->
            <div v-else-if="isBlinded(c) && !isMyComment(c) && !isAdmin && !revealedComments[c.id]" class="blinded comment-blinded">
              🙈 비추천이 많아 블라인드된 댓글입니다.
              <button type="button" class="reveal-btn" @click="toggleReveal(c)">그래도 보기</button>
            </div>
            <template v-else>
              <MarkdownViewer :content="c.content" class="comment-body" />
              <div class="comment-votes">
                <button
                  type="button" class="cvote up" :class="{ active: c.myVote === 'UP' }"
                  :disabled="isMyComment(c)"
                  :title="isMyComment(c) ? '본인 댓글은 추천할 수 없습니다' : ''"
                  @click="voteComment(c, 'UP')"
                >👍 {{ c.upCount || 0 }}</button>
                <button
                  type="button" class="cvote down" :class="{ active: c.myVote === 'DOWN' }"
                  :disabled="isMyComment(c)"
                  :title="isMyComment(c) ? '본인 댓글은 비추천할 수 없습니다' : ''"
                  @click="voteComment(c, 'DOWN')"
                >👎 {{ c.downCount || 0 }}</button>
                <button
                  v-if="!isAdmin && auth.user && c.authorId !== auth.user.id"
                  type="button" class="creport" @click="reportComment(c)"
                >🚩 신고</button>
                <button
                  v-if="isAdmin && c.blocked"
                  type="button" class="cunblock" @click="unblockComment(c)"
                >블라인드 해제</button>
              </div>
            </template>
          </li>
        </ul>
        <p v-if="!post.comments.length" class="msg">첫 댓글을 남겨보세요.</p>

        <!-- 댓글 목록 최하단(입력폼 위) 새로고침 -->
        <div class="comment-refresh">
          <button type="button" class="refresh-btn" :disabled="refreshingComments" @click="refreshComments">
            🔄 {{ refreshingComments ? '새로고침 중…' : '댓글 새로고침' }}
          </button>
        </div>

        <form v-if="!post.blocked" class="comment-form" @submit.prevent="addComment">
          <MarkdownEditor
            v-model="commentText"
            height="160px"
            initial-edit-type="wysiwyg"
            placeholder="댓글을 입력하세요"
          />
          <div class="comment-submit">
            <IconBtn icon="send" title="댓글 등록" variant="primary" type="submit" :disabled="submitting" />
          </div>
        </form>
      </section>
    </article>
  </section>
</template>

<style scoped>
.detail {
  max-width: 800px;
  margin: 0 auto;
}
.post-head {
  border: 1px solid var(--color-border);
  border-radius: 6px;
  background: var(--color-background-soft);
  padding: 1rem 1.25rem;
  margin-bottom: 1.25rem;
}
h1 {
  font-size: 1.5rem;
  margin-bottom: 0.5rem;
}
.meta {
  font-size: 0.85rem;
  color: var(--color-text);
  opacity: 0.85;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  flex-wrap: wrap;
}
.meta-author {
  font-weight: 600;
}
/* 추천/비추천 */
.vote-bar {
  display: flex;
  justify-content: center;
  gap: 0.75rem;
  padding: 0.5rem 0 1rem;
}
.vote-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.5rem 1.4rem;
  border-radius: 999px;
  font-size: 0.92rem;
}
.vote-btn b {
  font-weight: 700;
}
.vote-btn.up.active {
  border-color: hsla(160, 100%, 37%, 1);
  color: hsla(160, 100%, 37%, 1);
  background: hsla(160, 100%, 37%, 0.08);
}
.vote-btn.down.active {
  border-color: #e67e22;
  color: #e67e22;
  background: rgba(230, 126, 34, 0.08);
}
/* 추천자 */
.recommenders-wrap {
  margin-bottom: 0.75rem;
}
.recommenders {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  width: 100%;
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  background: var(--color-background-soft);
  cursor: pointer;
  text-align: left;
}
.recommenders:hover {
  background: var(--color-background-mute);
}
.rec-avatars {
  display: inline-flex;
}
.rec-avatar {
  margin-left: -4px;
  box-shadow: 0 0 0 2px var(--color-background-soft);
}
.rec-avatar:first-child {
  margin-left: 0;
}
.rec-label {
  font-size: 0.85rem;
  color: var(--color-text);
  opacity: 0.85;
}
.rec-toggle {
  margin-left: auto;
  font-size: 0.7rem;
  opacity: 0.6;
}
.rec-inline-list {
  list-style: none;
  margin: 0.4rem 0 0;
  padding: 0.55rem 0.65rem;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem 0.8rem;
}
.rec-inline-list li {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  white-space: nowrap; /* 이름이 잘리지 않도록 아바타+이름 단위로 줄바꿈 */
  flex: none;
}
.rec-name {
  font-size: 0.85rem;
}
.tags {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  padding: 0.75rem 0 1.25rem;
  border-top: 1px solid var(--color-border);
  margin-top: 0.5rem;
}
.tag {
  font-size: 0.8rem;
  color: hsla(160, 100%, 37%, 1);
}
.admin-banner {
  background: rgba(192, 57, 43, 0.1);
  border: 1px solid #c0392b;
  color: #c0392b;
  border-radius: 4px;
  padding: 0.5rem 0.75rem;
  margin-bottom: 1rem;
  font-size: 0.9rem;
}
.restricted {
  padding: 3rem 1rem;
  text-align: center;
  color: #c0392b;
  border: 1px dashed var(--color-border);
  border-radius: 6px;
  margin-bottom: 1.5rem;
}
.content {
  white-space: pre-wrap;
  line-height: 1.7;
  min-height: 120px;
  padding: 0.5rem 0 1.5rem;
}
button {
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-background-soft);
  color: var(--color-text);
  cursor: pointer;
}
button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
button.danger {
  border-color: #c0392b;
  color: #c0392b;
}
button.warn {
  border-color: #e67e22;
  color: #e67e22;
}
button.notice-btn {
  border-color: hsla(160, 100%, 37%, 1);
  color: hsla(160, 100%, 37%, 1);
}
.notice-badge {
  margin-right: 0.4rem;
  padding: 0.1rem 0.45rem;
  border-radius: 4px;
  background: hsla(160, 100%, 37%, 1);
  color: #fff;
  font-size: 0.8rem;
  font-weight: 700;
  vertical-align: middle;
}
.actions {
  display: flex;
  justify-content: space-between;
  border-top: 1px solid var(--color-border);
  padding-top: 1rem;
}
.right-actions {
  display: flex;
  gap: 0.5rem;
}
.comments {
  margin-top: 2rem;
}
.comments h2 {
  font-size: 1.1rem;
  margin-bottom: 0.75rem;
}
.comment-list {
  list-style: none;
}
.comment {
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--color-border);
}
.comment-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.85rem;
}
.comment-date {
  opacity: 0.7;
}
.comment-del {
  margin-left: auto;
  padding: 0.15rem 0.5rem;
  font-size: 0.78rem;
}
.comment-body {
  margin-top: 0.3rem;
}
.author-badge {
  padding: 0.05rem 0.35rem;
  border-radius: 3px;
  background: hsla(160, 100%, 37%, 1);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 700;
}
.hot-comment {
  background: rgba(231, 76, 60, 0.05);
  border-radius: 6px;
}
.hot-badge {
  padding: 0.05rem 0.35rem;
  border-radius: 3px;
  background: #e74c3c;
  color: #fff;
  font-size: 0.68rem;
  font-weight: 700;
}
.report-badge {
  padding: 0.05rem 0.35rem;
  border-radius: 3px;
  border: 1px solid #c0392b;
  color: #c0392b;
  font-size: 0.68rem;
  font-weight: 700;
}
.report-btn {
  padding: 0.45rem 0.9rem;
  border-radius: 4px;
  color: #c0392b;
  font-size: 0.85rem;
}
.creport {
  padding: 0.2rem 0.6rem;
  font-size: 0.8rem;
  border-radius: 999px;
  color: #c0392b;
  opacity: 0.85;
}
.cunblock {
  padding: 0.2rem 0.6rem;
  font-size: 0.8rem;
  border-radius: 999px;
  border-color: hsla(160, 100%, 37%, 1);
  color: hsla(160, 100%, 37%, 1);
}
.comment-votes {
  display: flex;
  gap: 0.4rem;
  margin-top: 0.4rem;
}
/* 블라인드 */
.blinded {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  padding: 1.5rem 1rem;
  border: 1px dashed var(--color-border);
  border-radius: 8px;
  color: var(--color-text);
  opacity: 0.85;
  font-size: 0.92rem;
}
.comment-blinded {
  padding: 0.7rem 0.8rem;
  margin-top: 0.3rem;
  font-size: 0.85rem;
}
.reveal-btn {
  padding: 0.3rem 0.8rem;
  border-radius: 999px;
  font-size: 0.82rem;
}
/* 댓글 새로고침 */
.comment-refresh {
  display: flex;
  justify-content: center;
  margin: 0.5rem 0 0.25rem;
}
.refresh-btn {
  padding: 0.35rem 1rem;
  border-radius: 999px;
  font-size: 0.85rem;
  color: var(--color-text);
}
.cvote {
  padding: 0.2rem 0.6rem;
  font-size: 0.8rem;
  border-radius: 999px;
}
.cvote.up.active {
  border-color: hsla(160, 100%, 37%, 1);
  color: hsla(160, 100%, 37%, 1);
}
.cvote.down.active {
  border-color: #e67e22;
  color: #e67e22;
}
.comment-form {
  margin-top: 1rem;
}
.comment-submit {
  display: flex;
  justify-content: flex-end;
  margin-top: 0.5rem;
}
.msg {
  margin: 0.75rem 0;
}
.msg.error {
  color: #c0392b;
}
</style>
