<template>
  <div class="people-view ms-ppl-detail-view">
    <div class="ms-ppl-topbar">
      <button class="ms-fm-btn" @click="router.back()">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none">
          <path d="M15 18l-6-6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
        </svg>
        返回
      </button>
    </div>

    <div v-if="loading" class="loading-state">
      <div class="spinner-lg"></div>
      <p>Loading...</p>
    </div>
    <template v-else-if="person">
      <div class="ms-ppl-detail-header">
        <div style="display:flex;flex-direction:column;align-items:center;gap:8px;flex-shrink:0;">
          <div class="ms-ppl-detail-avatar">
            <img v-if="profile" :src="profile" alt="">
            <svg v-else class="ms-silhouette" viewBox="0 0 120 120" fill="none">
              <circle cx="60" cy="45" r="25" fill="#d1d5db"/>
              <ellipse cx="60" cy="105" rx="40" ry="25" fill="#d1d5db"/>
            </svg>
          </div>
        </div>
        <div style="flex:1;min-width:0;">
          <div id="msPplInfoView">
            <div class="ms-ppl-detail-name-row">
              <button class="ms-ppl-star-btn" :class="{ starred: person.starred }" @click="toggleStar">☆</button>
              <div class="ms-ppl-view-box ms-ppl-view-name-box">{{ person.name || '—' }}</div>
            </div>
            <div class="ms-ppl-detail-aliases" v-if="person.metadata?.aliases?.length">
              <span v-for="(a, i) in person.metadata.aliases" :key="i" class="ms-ppl-alias-chip">{{ a.name }}</span>
            </div>
            <div class="ms-ppl-edit-fields" style="margin-top:4px;">
              <div class="ms-ppl-edit-field-row">
                <span class="ms-ppl-edit-label">角色</span>
                <div class="ms-ppl-view-box ms-ppl-view-field-box">{{ person.metadata?.role || '—' }}</div>
              </div>
              <div class="ms-ppl-edit-field-row ms-ppl-edit-field-row--top">
                <span class="ms-ppl-edit-label">描述</span>
                <div class="ms-ppl-view-box ms-ppl-view-notes-box">{{ person.metadata?.notes || '—' }}</div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <div class="ms-ppl-strip-wrap">
        <button class="ms-ppl-strip-add-btn" @click="showCandidates = true" title="加入相同人物">＋</button>
        <div class="ms-ppl-face-strip">
          <div v-for="f in faces.slice(0, 30)" :key="f.id" class="ms-ppl-strip-face">
            <div class="ms-ppl-strip-face-img">
              <img v-if="f.thumbUrl" :src="f.thumbUrl" alt="" loading="lazy" style="width:100%;height:100%;object-fit:cover;border-radius:8px;">
              <div v-else style="width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:#eef2ff;color:#6366f1;font-size:14px;font-weight:600;border-radius:8px;">{{ Math.round(f.confidence * 100) }}%</div>
            </div>
          </div>
        </div>
        <button v-if="faces.length > 30" class="ms-ppl-strip-arrow" @click="showAllFaces = !showAllFaces">›</button>
      </div>

      <div class="ms-ppl-media-label" v-if="mergedTraces.length">{{ mergedTraces.length }} segments</div>
      <div class="ms-ppl-media-grid">
        <div v-for="(m, i) in mergedTraces.slice(0, 20)" :key="i" class="ms-ppl-media-item" @click="playVideo(m.file_uuid, m.start, m.end)">
          <div class="ms-ppl-media-thumb">
            <img v-if="m.thumbUrl" :src="m.thumbUrl" alt="" loading="lazy" style="width:100%;height:100%;object-fit:cover;" @error="handleThumbError">
            <div class="ms-thumb-play-circle">
              <svg width="20" height="20" viewBox="0 0 24 24"><polygon points="6,4 20,12 6,20" fill="white"/></svg>
            </div>
            <span class="ms-ppl-media-dur">{{ (m.end - m.start).toFixed(1) }}s</span>
          </div>
          <div class="ms-ppl-media-info">
            <div class="ms-ppl-media-title">{{ m.count > 1 ? 'Merged ' + m.count + ' segments' : 'Segment' }}</div>
            <div class="ms-ppl-media-sub">{{ m.start.toFixed(1) }}s - {{ m.end.toFixed(1) }}s</div>
          </div>
        </div>
      </div>

      <div class="ms-ppl-delete-zone">
        <hr class="ms-ppl-delete-hr">
        <button class="ms-fm-btn ms-ppl-delete-zone-btn" @click="confirmDelete">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none">
            <polyline points="3 6 5 6 21 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></polyline>
            <path d="M19 6l-1 14H6L5 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
            <path d="M10 11v6M14 11v6" stroke="currentColor" stroke-width="2" stroke-linecap="round"></path>
          </svg>
          刪除此人物
        </button>
      </div>
    </template>
    <div v-else class="empty">
      Person not found: {{ route.params.uuid }}
      <br><br>
      <span style="font-size:12px;color:#9aa0a6;">People loaded: {{ peopleCount }}</span>
    </div>

    <div v-if="showCandidates" class="ms-modal-overlay show" @click.self="showCandidates = false">
      <div class="ms-modal ms-modal-merge">
        <button class="ms-fm-icon-btn close-btn" @click="showCandidates = false">×</button>
        <h2 class="ms-ppl-section-title">Bind Face</h2>
        <div class="ms-merge-grid">
          <div v-for="c in candidates" :key="c.id" class="ms-merge-face-card" @click="bindCandidate(c)">
            <div class="ms-merge-face-img">
              <img v-if="c.thumbUrl" :src="c.thumbUrl" alt="">
              <div v-else class="face-placeholder">{{ Math.round(c.confidence * 100) }}%</div>
            </div>
            <span class="ms-merge-face-name">{{ c.file_uuid?.slice(0, 8) }}... #{{ c.frame_number }}</span>
          </div>
        </div>
      </div>
    </div>

    <div v-if="showMerge" class="ms-modal-overlay show" @click.self="showMerge = false">
      <div class="ms-modal">
        <button class="ms-fm-icon-btn close-btn" @click="showMerge = false">×</button>
        <h2 class="ms-ppl-section-title">Merge Identity</h2>
        <input v-model="mergeTarget" class="merge-input" placeholder="Target identity UUID" />
        <div class="ms-modal-actions">
          <button class="ms-fm-btn ms-fm-btn-blue" :disabled="!mergeTarget" @click="confirmMerge">Merge</button>
        </div>
      </div>
    </div>

    <VideoPlayer v-if="playing" :file-uuid="currentVideo.fileUuid" :start-time="currentVideo.startTime" :end-time="currentVideo.endTime" :title="currentVideo.title" @close="playing = false" />
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { invoke } from '@tauri-apps/api/core'
import VideoPlayer from '../components/VideoPlayer.vue'

const route = useRoute()
const router = useRouter()

const person = ref<any>(null)
const loading = ref(true)
const profile = ref('')
const peopleCount = ref(0)
const faces = ref<any[]>([])
const traces = ref<any[]>([])
const mergedTraces = ref<any[]>([])
const playing = ref(false)
const currentVideo = ref({ fileUuid: '', startTime: 0, endTime: 0, title: '' })
const showCandidates = ref(false)
const showMerge = ref(false)
const mergeTarget = ref('')
const candidates = ref<any[]>([])
const showAllFaces = ref(false)

const CORE_API = 'http://localhost:3002'
const API_KEY = 'muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69'

onMounted(async () => {
  const uuid = route.params.uuid as string
  console.log('PersonDetailView mounted, uuid:', uuid)
  try {
    console.log('Calling getPeople with uuid:', uuid)
    const people: any = await invoke('get_people', { page: 1, perPage: 1000 })
    console.log('getPeople raw result:', JSON.stringify(people).slice(0, 200))
    console.log('getPeople result count:', Array.isArray(people) ? people.length : 'not array')
    peopleCount.value = Array.isArray(people) ? people.length : 0
    const found = (Array.isArray(people) ? people : []).find((p: any) => p.identity_uuid === uuid)
    console.log('Person found:', !!found, found?.name)
    if (found) {
      person.value = { ...found, status: found.status || 'confirmed' }
      await loadProfile(uuid)
      await loadFaces(uuid)
      await loadMedia(uuid)
    }
  } catch (e) {
    console.error('Failed to load person:', e)
  } finally {
    loading.value = false
  }
  loadCandidates()
})

async function loadProfile(uuid: string) {
  try { profile.value = await invoke('get_identity_profile', { uuid }) } catch {}
}

async function loadFaces(uuid: string) {
  try {
    const result: any = await invoke('getFaces', { uuid, perPage: 1000 })
    const items = Array.isArray(result) ? result : []
    faces.value = items.map((f: any) => ({
      ...f,
      thumbUrl: f.file_uuid ? `${CORE_API}/api/v1/file/${f.file_uuid}/thumbnail?api_key=${API_KEY}&frame=${f.frame_number || 0}` : ''
    }))
  } catch (e) { console.error('Failed to load faces:', e) }
}

async function loadMedia(uuid: string) {
  try {
    const result: any = await invoke('getTraces', { uuid, perPage: 1000 })
    const rawItems = Array.isArray(result) ? result : []
    rawItems.sort((a: any, b: any) => (a.first_sec || 0) - (b.first_sec || 0))
    
    const merged: any[] = []
    let cur: any = null
    rawItems.forEach((item: any) => {
      const st = item.first_sec || 0
      const en = item.last_sec || 0
      const fu = item.file_uuid || ''
      if (cur && fu === cur.file_uuid && (st - cur.end) < 30) {
        cur.end = Math.max(cur.end, en)
        cur.count++
      } else {
        if (cur) merged.push(cur)
        cur = { file_uuid: fu, start: st, end: en, count: 1, first_frame: item.first_frame || 0 }
      }
    })
    if (cur) merged.push(cur)
    
    mergedTraces.value = merged.map((m: any) => ({
      ...m,
      thumbUrl: m.file_uuid ? `${CORE_API}/api/v1/file/${m.file_uuid}/thumbnail?api_key=${API_KEY}&frame=${m.first_frame || Math.floor(m.start * 24)}` : ''
    }))
  } catch (e) { console.error('Failed to load media:', e) }
}

async function loadCandidates() {
  try {
    const result: any = await invoke('get_face_candidates', { page: 1, perPage: 100 })
    candidates.value = (Array.isArray(result) ? result : []).map((c: any) => ({
      ...c,
      thumbUrl: c.file_uuid ? `${CORE_API}/api/v1/file/${c.file_uuid}/thumbnail?api_key=${API_KEY}&frame=${c.frame_number || 0}` : ''
    }))
  } catch (e) { console.error('Failed to load candidates:', e) }
}

function handleThumbError(e: Event) {
  const img = e.target as HTMLImageElement
  img.style.display = 'none'
}

async function toggleStar() {
  if (!person.value) return
  person.value.starred = !person.value.starred
}

async function confirmDelete() {
  if (!person.value || !confirm(`Delete "${person.value.name}"?`)) return
  try {
    await invoke('delete_identity', { uuid: person.value.identity_uuid })
    router.back()
  } catch (e) { console.error('Failed to delete:', e) }
}

async function bindCandidate(c: any) {
  if (!person.value) return
  try {
    await invoke('bind_face', { uuid: person.value.identity_uuid, faceId: String(c.id), fileUuid: c.file_uuid })
    showCandidates.value = false
    await loadFaces(person.value.identity_uuid)
  } catch (e) { console.error('Bind failed:', e) }
}

async function confirmMerge() {
  if (!person.value || !mergeTarget.value) return
  try {
    await invoke('merge_identities', { uuid: person.value.identity_uuid, intoUuid: mergeTarget.value })
    router.back()
  } catch (e) { console.error('Merge failed:', e) }
}

function playVideo(fileUuid: string, start: number, end: number) {
  currentVideo.value = { fileUuid, startTime: start, endTime: end, title: `${person.value?.name} - ${start.toFixed(1)}s-${end.toFixed(1)}s` }
  playing.value = true
}

function formatTime(sec: number): string {
  const m = Math.floor(sec / 60); const s = Math.floor(sec % 60)
  return `${m}:${s.toString().padStart(2, '0')}`
}
</script>

<style scoped>
.people-view { max-width: 1200px; padding-top: 20px; }
.ms-ppl-topbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 24px; margin-top: 20px; }
.loading-state, .empty { text-align: center; padding: 60px 0; color: #5f6368; }
.spinner-lg { width: 24px; height: 24px; border: 3px solid #e8eaed; border-top-color: #202124; border-radius: 50%; animation: spin 0.7s linear infinite; margin: 0 auto 12px; }
@keyframes spin { to { transform: rotate(360deg); } }
.close-btn { position: absolute; top: 16px; right: 16px; }
.ms-ppl-detail-header { display: flex; align-items: flex-start; gap: 22px; margin-bottom: 28px; position: relative; margin-top: 20px; }
.ms-ppl-detail-avatar { width: 120px; height: 120px; border-radius: 20px; background: #e0e0e0; flex-shrink: 0; overflow: hidden; }
.ms-ppl-detail-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 20px; }
.ms-ppl-detail-name-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.ms-ppl-star-btn { font-size: 20px; background: transparent; border: none; cursor: pointer; outline: none; line-height: 1; color: #d1d5db; transition: color .15s; padding: 0; flex-shrink: 0; }
.ms-ppl-star-btn.starred { color: #f59e0b; }
.ms-ppl-detail-aliases { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 12px; }
.ms-ppl-alias-chip { display: inline-flex; align-items: center; background: #f0f0f0; border-radius: 999px; padding: 3px 10px; font-size: 11.5px; color: #5f6368; }
.ms-ppl-edit-fields { display: flex; flex-direction: column; gap: 10px; margin-bottom: 16px; }
.ms-ppl-edit-field-row { display: flex; align-items: center; gap: 12px; }
.ms-ppl-edit-field-row--top { align-items: flex-start; }
.ms-ppl-edit-label { font-family: 'DM Sans', 'Noto Sans TC', sans-serif; font-size: 12px; font-weight: 700; color: #202124; letter-spacing: .03em; min-width: 30px; text-align: right; flex-shrink: 0; padding-top: 2px; }
.ms-ppl-view-box { font-family: 'DM Sans', 'Noto Sans TC', sans-serif; font-size: 13.5px; color: #202124; min-height: 24px; display: flex; align-items: center; word-break: break-word; padding: 2px 0; }
.ms-ppl-view-name-box { font-size: 20px; font-weight: 700; flex: 1; min-width: 0; }
.ms-ppl-view-field-box { flex: 1; min-width: 0; color: #3c4043; }
.ms-ppl-view-notes-box { flex: 1; min-width: 0; min-height: 24px; align-items: flex-start; color: #9aa0a6; font-size: 13px; white-space: pre-wrap; }
.ms-ppl-strip-wrap { display: flex; align-items: center; gap: 10px; margin-bottom: 28px; }
.ms-ppl-strip-add-btn { width: 52px; height: 52px; border-radius: 12px; border: 1.5px dashed #bdc1c6; background: #fff; font-size: 20px; color: #bdc1c6; display: grid; place-items: center; cursor: pointer; outline: none; flex-shrink: 0; transition: border-color .15s, color .15s; }
.ms-ppl-strip-add-btn:hover { border-color: #202124; color: #202124; }
.ms-ppl-face-strip { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 4px; scrollbar-width: thin; flex: 1; }
.ms-ppl-strip-face { position: relative; flex-shrink: 0; cursor: pointer; }
.ms-ppl-strip-face-img { width: 52px; height: 52px; border-radius: 12px; border: 2px solid transparent; background: #e8eaed; overflow: hidden; transition: border-color .15s; }
.ms-ppl-strip-face:hover .ms-ppl-strip-face-img { border-color: #202124; }
.ms-ppl-strip-arrow { width: 28px; height: 28px; border-radius: 50%; border: 1.5px solid #d1d5db; background: #fff; font-size: 18px; display: grid; place-items: center; cursor: pointer; color: #5f6368; outline: none; flex-shrink: 0; transition: background .15s; }
.ms-ppl-strip-arrow:hover { background: #f3f4f6; color: #202124; }
.ms-ppl-media-label { font-size: 13px; color: #5f6368; margin-bottom: 16px; }
.ms-ppl-media-item { cursor: pointer; border-radius: 12px; overflow: visible; background: #f0f0f0; transition: transform .15s, box-shadow .15s; border: 1px solid #eee; }
.ms-ppl-media-item:hover { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(0,0,0,.1); }
.ms-ppl-media-thumb { position: relative; width: 100%; aspect-ratio: 16/9; overflow: hidden; background: #e8eaed; border-radius: 12px 12px 0 0; }
.ms-thumb-play-circle { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: rgba(0,0,0,0.18); border-radius: 12px 12px 0 0; }
.ms-thumb-play-circle svg { width: 38px; height: 38px; opacity: .7; transition: opacity .15s, transform .15s; }
.ms-ppl-media-item:hover .ms-thumb-play-circle svg { opacity: 1; transform: scale(1.08); }
.ms-ppl-media-dur { position: absolute; bottom: 5px; right: 7px; background: rgba(0,0,0,.5); color: #fff; font-size: 10px; padding: 1px 5px; border-radius: 3px; }
.ms-ppl-media-info { padding: 8px 10px 10px; background: #fff; }
.ms-ppl-media-title { font-size: 12px; font-weight: 600; color: #202124; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: 2px; }
.ms-ppl-media-sub { font-size: 10.5px; color: #9aa0a6; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ms-ppl-delete-zone { margin-top: 48px; padding-bottom: 32px; }
.ms-ppl-delete-hr { border: none; border-top: 1.5px solid #f3f4f6; margin: 0 0 20px; }
.ms-ppl-delete-zone-btn { color: #d93025; border-color: #fecaca; background: #fff; }
.ms-ppl-delete-zone-btn:hover { background: #fef2f2; border-color: #d93025; }
.face-placeholder { font-size: 0.6rem; color: #5f6368; }
.merge-input { width: 100%; padding: 10px 14px; border: 1.5px solid #d1d5db; border-radius: 10px; margin-bottom: 16px; font-size: 0.9rem; outline: none; }
.merge-input:focus { border-color: #202124; }
.ms-modal-actions { display: flex; justify-content: flex-end; }
h2 { margin: 0 0 16px; font-size: 1rem; }
.ms-merge-grid { display: flex; flex-wrap: wrap; gap: 16px; max-height: 50vh; overflow-y: auto; }
.ms-silhouette { width: 100%; height: 100%; }
</style>
