<template>
  <div class="space-y-4">
    <!-- Header -->
    <div class="flex items-center justify-between">
      <h3 class="text-xl font-semibold flex items-center gap-2">
        <span>臉部追蹤</span>
        <span class="text-sm text-gray-400 font-normal">({{ totalTraces }} 個追蹤, {{ totalFaces }} 個臉孔)</span>
      </h3>
      <div class="flex items-center gap-2">
        <select v-model="sortBy" @change="loadTraces"
          class="bg-gray-700 text-sm rounded px-3 py-1.5 border border-gray-600">
          <option value="face_count">臉孔數</option>
          <option value="duration">持續時間</option>
          <option value="first_appearance">首次出現</option>
        </select>
        <select v-model="limit" @change="loadTraces"
          class="bg-gray-700 text-sm rounded px-3 py-1.5 border border-gray-600">
          <option :value="50">50 筆</option>
          <option :value="100">100 筆</option>
          <option :value="500">500 筆</option>
        </select>
      </div>
    </div>

    <!-- Step 3: Filter Bar -->
    <div class="bg-gray-750 rounded-lg p-4 border border-gray-700 grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
      <div>
        <label class="text-gray-400 text-xs block mb-1">最少臉孔</label>
        <input type="number" min="1" max="100" v-model.number="filterMinFaces"
          @change="loadTraces"
          class="w-full bg-gray-700 rounded px-2 py-1.5 border border-gray-600 text-white" />
      </div>
      <div>
        <label class="text-gray-400 text-xs block mb-1">最小信心</label>
        <input type="range" min="0" max="100" v-model.number="filterMinConfPct"
          @change="loadTraces"
          class="w-full accent-blue-500" />
        <span class="text-gray-500 text-xs">{{ filterMinConfPct }}%</span>
      </div>
      <div>
        <label class="text-gray-400 text-xs block mb-1">最大信心</label>
        <input type="range" min="0" max="100" v-model.number="filterMaxConfPct"
          @change="loadTraces"
          class="w-full accent-blue-500" />
        <span class="text-gray-500 text-xs">{{ filterMaxConfPct }}%</span>
      </div>
      <div class="flex items-end">
        <button @click="resetFilters"
          class="px-3 py-1.5 bg-gray-700 hover:bg-gray-600 rounded text-xs transition">
          重設
        </button>
      </div>
    </div>

    <!-- Step 2: Timeline Bar Chart -->
    <div v-if="Object.keys(traces).length > 0" class="bg-gray-800 rounded-lg p-4 border border-gray-700 overflow-x-auto">
      <div class="relative" :style="{ height: timelineHeight + 'px' }">
        <!-- Time axis -->
        <div class="absolute bottom-0 left-0 right-0 flex text-xs text-gray-500">
          <div v-for="t in timeTicks" :key="t"
            class="flex-1 border-l border-gray-700 pl-1">
            {{ t }}s
          </div>
        </div>
        <!-- Trace bars -->
        <div v-for="(trace, i) in topTracesForTimeline" :key="trace.trace_id"
          class="absolute left-0 right-0 flex items-center cursor-pointer hover:opacity-80 transition"
          :style="{
            bottom: barPosition(i) + '%',
            height: barHeight() + '%'
          }"
          @click="toggleExpand(trace.trace_id)">
          <div class="h-full rounded-sm transition-all"
            :style="{
              width: barWidthPct(trace) + '%',
              backgroundColor: barColor(trace.avg_confidence),
              marginLeft: barOffsetPct(trace) + '%'
            }"
            :title="`#${trace.trace_id}: ${trace.face_count} faces`">
          </div>
          <span v-if="barWidthPct(trace) > 8"
            class="absolute left-1 text-xs text-white truncate pointer-events-none">
            #{{ trace.trace_id }}
          </span>
        </div>
      </div>
    </div>

    <!-- Grid -->
    <div v-if="loading" class="flex justify-center py-8">
      <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
    </div>

    <div v-else-if="error" class="bg-red-900/30 text-red-300 p-4 rounded-lg text-sm">
      {{ error }}
    </div>

    <div v-else-if="Object.keys(traces).length === 0" class="text-gray-500 text-center py-8 text-sm">
      尚無臉部追蹤資料
    </div>

    <div v-else class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3">
      <div v-for="trace in traces" :key="trace.trace_id"
        class="bg-gray-800 rounded-lg border border-gray-700 overflow-hidden hover:border-blue-500/50 transition cursor-pointer"
        @click="toggleExpand(trace.trace_id)">
        <div class="aspect-video bg-gray-900 relative overflow-hidden">
          <img v-if="trace.sample_face_id"
            :src="`${apiBase}/api/v1/file/${fileUuid}/trace/${trace.trace_id}/video`"
            :alt="`Trace ${trace.trace_id}`"
            class="w-full h-full object-cover"
            loading="lazy" />
          <div class="absolute top-2 left-2 bg-black/70 text-xs px-2 py-0.5 rounded font-mono">
            #{{ trace.trace_id }}
          </div>
          <div class="absolute bottom-2 right-2 bg-black/70 text-xs px-2 py-0.5 rounded"
            :class="confidenceColor(trace.avg_confidence)">
            {{ (trace.avg_confidence * 100).toFixed(0) }}%
          </div>
        </div>
        <div class="p-3 text-sm space-y-1">
          <div class="flex justify-between text-gray-400">
            <span>臉孔: <strong class="text-white">{{ trace.face_count }}</strong></span>
            <span>{{ trace.first_sec.toFixed(1) }}s - {{ trace.last_sec.toFixed(1) }}s</span>
          </div>
          <div class="flex justify-between text-gray-400">
            <span>幀: {{ trace.first_frame }}-{{ trace.last_frame }}</span>
            <span>持續 {{ trace.duration_sec.toFixed(1) }}s</span>
          </div>
          <div class="w-full bg-gray-700 rounded-full h-1 mt-1">
            <div class="bg-blue-500 h-1 rounded-full transition-all"
              :style="{ width: barWidth(trace) }">
            </div>
          </div>
        </div>

        <!-- Step 1: Expandable Detail -->
        <div v-if="expandedTrace === trace.trace_id"
          class="border-t border-gray-700 bg-gray-850"
          @click.stop>
          <div class="p-3">
            <div v-if="loadingFaces[trace.trace_id]" class="flex justify-center py-4">
              <div class="animate-spin rounded-full h-6 w-6 border-b-2 border-blue-500"></div>
            </div>
            <div v-else-if="faceErrors[trace.trace_id]" class="text-red-400 text-xs">
              {{ faceErrors[trace.trace_id] }}
            </div>
            <div v-else-if="traceFaces[trace.trace_id]?.length" class="space-y-2">
              <div class="text-xs text-gray-500 mb-2">
                共 {{ faceTotals[trace.trace_id] || 0 }} 個臉孔偵測
              </div>
              <div class="grid grid-cols-4 sm:grid-cols-6 md:grid-cols-8 gap-1.5 max-h-48 overflow-y-auto">
                <div v-for="face in traceFaces[trace.trace_id]" :key="face.id"
                  class="relative aspect-square bg-gray-900 rounded overflow-hidden group"
                  :class="face.interpolated ? 'opacity-40' : ''">
                  <img v-if="!face.interpolated"
                    :src="`${apiBase}/api/v1/file/${fileUuid}/thumbnail?frame=${face.start_frame}&x=${face.x}&y=${face.y}&w=${face.width}&h=${face.height}`"
                    :alt="`Frame ${face.start_frame}`"
                    class="w-full h-full object-cover"
                    loading="lazy"
                    @error="onImgError" />
                  <div v-else
                    class="w-full h-full flex items-center justify-center border border-dashed border-gray-600 rounded text-gray-600 text-[9px]">
                    {{ face.start_frame }}
                  </div>
                  <div class="absolute bottom-0 inset-x-0 bg-black/70 text-[9px] text-gray-300 px-1 truncate opacity-0 group-hover:opacity-100 transition">
                    #{{ face.start_frame }} {{ face.interpolated ? '' : (face.confidence * 100).toFixed(0) + '%' }}
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'
import { getCurrentConfig, httpFetch } from '@/api/client'

const props = defineProps<{
  fileUuid: string
  totalDuration: number
}>()

const apiBase = ref('')
const traces = ref<any[]>([])
const totalTraces = ref(0)
const totalFaces = ref(0)
const loading = ref(false)
const error = ref('')
const sortBy = ref('face_count')
const limit = ref(100)

// Filter state
const filterMinFaces = ref(1)
const filterMinConfPct = ref(0)
const filterMaxConfPct = ref(100)

// Expanded trace detail
const expandedTrace = ref<number | null>(null)
const traceFaces = ref<Record<number, any[]>>({})
const faceTotals = ref<Record<number, number>>({})
const loadingFaces = ref<Record<number, boolean>>({})
const faceErrors = ref<Record<number, string>>({})

const duration = computed(() => props.totalDuration || 1 || 3000)

// Step 2: Timeline helpers
const timelineMaxTraces = 30
const timelineHeight = 120
const topTracesForTimeline = computed(() => {
  const sorted = [...traces.value].sort((a, b) => b.face_count - a.face_count)
  return sorted.slice(0, timelineMaxTraces)
})

const timeTicks = computed(() => {
  const dur = duration.value
  const step = Math.max(30, Math.round(dur / 10 / 30) * 30)
  const ticks: number[] = []
  for (let t = 0; t <= dur; t += step) {
    ticks.push(t)
  }
  return ticks
})

function barPosition(index: number): number {
  const count = topTracesForTimeline.value.length
  const gap = 1
  const barH = Math.max(8, (100 - gap * (count + 1)) / count)
  return gap + index * (barH + gap)
}

function barHeight(): number {
  const count = topTracesForTimeline.value.length
  const gap = 1
  const barH = Math.max(8, (100 - gap * (count + 1)) / count)
  return barH
}

function barWidthPct(trace: any): number {
  const dur = duration.value
  if (!dur) return 0
  return Math.max(0.5, ((trace.last_sec || 1) - (trace.first_sec || 0)) / dur * 100)
}

function barOffsetPct(trace: any): number {
  const dur = duration.value
  if (!dur) return 0
  return ((trace.first_sec || 0) / dur) * 100
}

function barColor(conf: number): string {
  if (conf >= 0.8) return 'rgba(74, 222, 128, 0.7)'
  if (conf >= 0.6) return 'rgba(250, 204, 21, 0.7)'
  return 'rgba(248, 113, 113, 0.7)'
}

function confidenceColor(conf: number): string {
  if (conf >= 0.8) return 'text-green-400'
  if (conf >= 0.6) return 'text-yellow-400'
  return 'text-red-400'
}

function barWidth(trace: any): string {
  const pct = totalTraces.value > 0
    ? (trace.face_count / (totalFaces.value || 1)) * 100
    : 0
  return `${Math.min(pct, 100)}%`
}

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

function resetFilters() {
  filterMinFaces.value = 1
  filterMinConfPct.value = 0
  filterMaxConfPct.value = 100
  loadTraces()
}

async function toggleExpand(traceId: number) {
  if (expandedTrace.value === traceId) {
    expandedTrace.value = null
    return
  }
  expandedTrace.value = traceId
  if (!traceFaces.value[traceId]) {
    await loadTraceFaces(traceId)
  }
}

async function loadTraceFaces(traceId: number) {
  loadingFaces.value[traceId] = true
  faceErrors.value[traceId] = ''
  try {
    const config = getCurrentConfig()
    const data = await httpFetch<any>(
      `${config.api_base_url}/api/v1/file/${props.fileUuid}/trace/${traceId}/faces?limit=200&interpolate=true`,
    )
    traceFaces.value[traceId] = data.faces || []
    faceTotals.value[traceId] = data.total || 0
  } catch (e: any) {
    faceErrors.value[traceId] = e?.message || '載入失敗'
  } finally {
    loadingFaces.value[traceId] = false
  }
}

async function loadTraces() {
  loading.value = true
  error.value = ''
  try {
    const config = getCurrentConfig()
    apiBase.value = config.api_base_url

    const apiSort = sortBy.value === 'face_count' ? 'face_count'
      : sortBy.value === 'duration' ? 'duration'
      : 'first_appearance'

    const data = await httpFetch<any>(
      `${config.api_base_url}/api/v1/file/${props.fileUuid}/face_trace/sortby`,
      {
        method: 'POST',
        body: JSON.stringify({
          sort_by: apiSort,
          limit: limit.value,
          min_faces: filterMinFaces.value,
          min_confidence: filterMinConfPct.value / 100,
          max_confidence: filterMaxConfPct.value / 100,
        })
      }
    )
    traces.value = data.traces || []
    totalTraces.value = data.total_traces || 0
    totalFaces.value = data.total_faces || 0
  } catch (e: any) {
    error.value = e?.message || '載入臉部追蹤資料失敗'
  } finally {
    loading.value = false
  }
}

onMounted(() => {
  loadTraces()
})
</script>
