<script setup lang="ts">
// 연결된 회의실 — 상단 바 + (스피커/그리드 뷰) 본문 + 오른쪽 패널(참여자/채팅) + 컨트롤 바.
// 모든 라이브 상태(participants/featuredIdentity/mic/cam/messages)는 부모(MeetingPage)가 주입한다.
import { computed, ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import type { Participant } from 'livekit-client'
import ParticipantTile from './ParticipantTile.vue'
import MeetingIcon from './MeetingIcon.vue'
import MeetingControlBar from './MeetingControlBar.vue'
import MeetingSidePanel from './MeetingSidePanel.vue'
import type { ChatMessage } from '@/types/meeting'

interface Props {
  roomName: string
  participants: Participant[]
  featuredIdentity: string | null
  localId: string | null
  micEnabled: boolean
  camEnabled: boolean
  isHost: boolean
  messages: ChatMessage[]
  // 말하는 사람 하이라이트 사용 여부(기본 on)
  highlight?: boolean
}
const props = withDefaults(defineProps<Props>(), { highlight: true })
const emit = defineEmits<{
  (e: 'toggle-mic'): void
  (e: 'toggle-cam'): void
  (e: 'promote', identity: string): void
  (e: 'send', text: string): void
  (e: 'leave'): void
}>()

// 한 페이지에 보일 참여자 수 — 스피커 뷰는 진행자(스테이지) 제외 나머지 최대 50명,
// 그리드 뷰는 전원 기준 50명. 초과분만 페이지네이션으로 넘긴다.
const PER_PAGE = 50

const page = ref(0)
const panel = ref<'people' | 'chat' | null>(null)
const unread = ref(0)

function isHostMeta(p: Participant): boolean {
  if (!p.metadata) return false
  try {
    return (JSON.parse(p.metadata) as { role?: string }).role === 'host'
  } catch {
    return false
  }
}

// --- 레이아웃 검증용 가상 참여자(개발 모드 전용) ---
// 사용법: /meeting/<방>?mock=100  → 미디어 없이 타일만 N명 추가(프로덕션 빌드에선 비활성).
const route = useRoute()
const MOCK_NAMES = [
  '김민준',
  '이서연',
  '박지후',
  '최예은',
  '정도윤',
  '강하늘',
  '윤시우',
  '임수아',
  '한지안',
  '오재현',
]
function makeMock(i: number): Participant {
  const name = `${MOCK_NAMES[i % MOCK_NAMES.length]}${i + 1}`
  return {
    sid: `mock-${i}`,
    identity: `mock-${i}`,
    name,
    isMicrophoneEnabled: i % 3 !== 0,
    isSpeaking: i % 7 === 0,
    connectionQuality: i % 5 === 0 ? 'poor' : i % 3 === 0 ? 'good' : 'excellent',
    metadata: undefined,
    getTrackPublication: () => undefined,
    on() {
      return this
    },
    off() {
      return this
    },
  } as unknown as Participant
}
const mockCount = computed(() => {
  if (!import.meta.env.DEV) return 0
  const n = Number(route.query.mock)
  return Number.isFinite(n) && n > 0 ? Math.min(Math.floor(n), 200) : 0
})
const mocks = computed<Participant[]>(() =>
  Array.from({ length: mockCount.value }, (_, i) => makeMock(i)),
)
// 실제 참여자 + 가상 참여자
const allParticipants = computed<Participant[]>(() =>
  mockCount.value ? [...props.participants, ...mocks.value] : props.participants,
)

// 스테이지에 올릴 참여자 — 승격됨 > 진행자 > 첫 참여자
const featured = computed<Participant | null>(() => {
  const list = allParticipants.value
  if (!list.length) return null
  if (props.featuredIdentity) {
    const f = list.find((p) => p.identity === props.featuredIdentity)
    if (f) return f
  }
  return list.find(isHostMeta) ?? list[0] ?? null
})

// 스테이지(진행자) 제외 나머지 — 썸네일 그리드에 표시
const others = computed(() =>
  allParticipants.value.filter((p) => p !== featured.value),
)
const pageCount = computed(() =>
  Math.max(1, Math.ceil(others.value.length / PER_PAGE)),
)
const safePage = computed(() => Math.min(page.value, pageCount.value - 1))
const pageSlice = computed(() => {
  const start = safePage.value * PER_PAGE
  return others.value.slice(start, start + PER_PAGE)
})

function togglePanel(tab: 'people' | 'chat') {
  panel.value = panel.value === tab ? null : tab
  if (panel.value === 'chat') unread.value = 0
}
function setTab(tab: 'people' | 'chat') {
  panel.value = tab
  if (tab === 'chat') unread.value = 0
}

// 채팅이 닫혀 있을 때 도착한 상대 메시지를 미읽음으로 집계
watch(
  () => props.messages.length,
  (len, prev) => {
    const added = props.messages.slice(prev ?? 0)
    if (panel.value !== 'chat') {
      unread.value += added.filter((m) => !m.self).length
    }
  },
)
</script>

<template>
  <div
    class="room"
    :class="{ 'panel-open': panel }"
  >
    <!-- 상단 바 -->
    <div class="room-bar">
      <div class="rb-left">
        <span class="rb-live"><i />LIVE</span>
        <span class="rb-name">{{ roomName }}</span>
      </div>
      <div class="rb-right">
        <span class="rb-count"><MeetingIcon name="users" />{{ allParticipants.length }}명</span>
      </div>
    </div>

    <!-- 본문 -->
    <div class="room-body">
      <div class="room-main">
        <!-- 축소된 스테이지(위) + 썸네일 그리드(아래) -->
        <div class="speaker-wrap">
          <div class="stage">
            <ParticipantTile
              v-if="featured"
              :key="featured.identity"
              :participant="featured"
              featured
              :is-local="featured.identity === localId"
              :highlight="highlight"
            />
            <div
              v-else
              class="stage-empty"
            >
              참여자를 기다리는 중…
            </div>
          </div>
          <div
            v-if="others.length"
            class="thumbs"
          >
            <div class="thumb-scroll">
              <div class="thumb-grid">
                <ParticipantTile
                  v-for="p in pageSlice"
                  :key="p.sid || p.identity"
                  :participant="p"
                  :is-local="p.identity === localId"
                  :can-promote="isHost"
                  :highlight="highlight"
                  @promote="(id) => emit('promote', id)"
                />
              </div>
            </div>
            <div
              v-if="pageCount > 1"
              class="pager"
            >
              <button
                type="button"
                class="pg-btn"
                :disabled="safePage === 0"
                @click="page = safePage - 1"
              >
                <MeetingIcon name="left" />
              </button>
              <span class="pg-info">썸네일 · {{ safePage + 1 }}/{{ pageCount }}</span>
              <button
                type="button"
                class="pg-btn"
                :disabled="safePage >= pageCount - 1"
                @click="page = safePage + 1"
              >
                <MeetingIcon name="right" />
              </button>
            </div>
          </div>
        </div>
      </div>

      <!-- 오른쪽 패널 -->
      <MeetingSidePanel
        v-if="panel"
        :tab="panel"
        :participants="allParticipants"
        :featured-id="featured?.identity ?? null"
        :local-id="localId"
        :is-host="isHost"
        :messages="messages"
        @tab="setTab"
        @close="panel = null"
        @promote="(id) => emit('promote', id)"
        @send="(t) => emit('send', t)"
      />
    </div>

    <!-- 컨트롤 바 -->
    <MeetingControlBar
      pos="bottom"
      :mic-enabled="micEnabled"
      :cam-enabled="camEnabled"
      :chat-open="panel === 'chat'"
      :people-open="panel === 'people'"
      :unread="unread"
      @toggle-mic="emit('toggle-mic')"
      @toggle-cam="emit('toggle-cam')"
      @toggle-chat="togglePanel('chat')"
      @toggle-people="togglePanel('people')"
      @leave="emit('leave')"
    />
  </div>
</template>

<style scoped>
.room {
  height: 100%;
  display: flex;
  flex-direction: column;
  position: relative;
}
.room-bar {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  height: 3.5rem;
  flex-shrink: 0;
  padding: 0 1.125rem;
  border-bottom: 1px solid var(--d-border);
  background: var(--d-panel);
}
.rb-left {
  display: flex;
  align-items: center;
  gap: 0.6875rem;
  min-width: 0;
}
.rb-live {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.6875rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.05em;
  color: #ff5a6e;
}
.rb-live i {
  width: 0.4375rem;
  height: 0.4375rem;
  border-radius: 50%;
  background: #ff5a6e;
  animation: livedot 1.6s infinite;
}
@keyframes livedot {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.35;
  }
}
.rb-name {
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1;
  color: var(--d-text);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rb-right {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.rb-count {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--d-text-2);
}
.rb-count svg {
  width: 0.9375rem;
  height: 0.9375rem;
}
.room-body {
  flex: 1;
  display: flex;
  min-height: 0;
}
.room-main {
  flex: 1;
  min-width: 0;
  padding: 1rem 1.125rem 6.25rem;
}

/* 스피커 뷰 — 위: 축소된 스테이지 / 아래: 썸네일 그리드(50명 채움) */
.speaker-wrap {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
  height: 100%;
  min-height: 0;
}
.stage {
  flex: 0 0 45%;
  min-height: 0;
  display: flex;
  justify-content: center;
}
/* 축소된 스테이지에서 큰 화면은 16:9 비율 유지 + 높이에 맞춰 중앙 정렬 */
.stage :deep(.tile.featured) {
  width: auto;
  max-width: 100%;
  aspect-ratio: 16 / 9;
}
.stage-empty {
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  color: var(--d-text-3);
  border: 1px dashed var(--d-border);
  border-radius: 0.875rem;
}
.thumbs {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
}
.thumb-scroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding-right: 0.125rem;
  scrollbar-width: thin;
  scrollbar-color: var(--d-border) transparent;
}
.thumb-scroll::-webkit-scrollbar {
  width: 0.4375rem;
}
.thumb-scroll::-webkit-scrollbar-thumb {
  background: var(--d-border);
  border-radius: 0.25rem;
}
.thumb-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
  gap: 0.5rem;
  align-content: start;
}

/* 페이지네이션 */
.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  flex-shrink: 0;
}
.pg-btn {
  width: 1.875rem;
  height: 1.875rem;
  border: 1px solid var(--d-border);
  background: var(--d-panel-2);
  color: var(--d-text-2);
  border-radius: 0.4375rem;
  cursor: pointer;
  display: grid;
  place-items: center;
}
.pg-btn svg {
  width: 0.9375rem;
  height: 0.9375rem;
}
.pg-btn:hover:not(:disabled) {
  color: var(--d-text);
  border-color: var(--d-text-3);
}
.pg-btn:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}
.pg-info {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--d-text-3);
}
</style>
