<script setup lang="ts">
// Tier 2 Block E — host analytics dashboard card. Shown on the event
// detail page; viewer+ role.
//
// Charts are inline SVG rather than chart.js — we avoid the ~70kB bundle
// hit for charts this small, and keep the page server-renderable. If the
// host's expectations grow (zoom, tooltips, animations) chart.js becomes
// the right call.

interface Overview {
  invited: number
  attending: number
  declined: number
  maybe: number
  pending: number
  plus_ones_total: number
}

interface AnalyticsPayload {
  overview: Overview
  response_rate: { date: string; count: number }[]
  funnel: { invited: number; opened: number; responded: number }
  time_to_respond: { label: string; count: number }[]
  plus_ones: { label: string; count: number }[]
  channels: { source: string; invited: number; attending: number }[]
  stale_guests: {
    guest_id: string
    name: string
    email?: string | null
    has_opened: boolean
    invited_at: string
  }[]
  generated_at: string
}

const props = defineProps<{ eventId: string }>()
const config = useRuntimeConfig()
const auth = useAuth()

const data = ref<AnalyticsPayload | null>(null)
const loading = ref(true)
const error = ref<string | null>(null)

async function refresh() {
  loading.value = true
  error.value = null
  try {
    data.value = await useApi<AnalyticsPayload>(`/events/${props.eventId}/analytics?days=30`)
  } catch (e: any) {
    error.value = useErrMessage(e, 'Could not load analytics')
  } finally {
    loading.value = false
  }
}
onMounted(refresh)

const responseRateMax = computed(() => {
  const series = data.value?.response_rate ?? []
  return Math.max(1, ...series.map((p) => p.count))
})

const plusOnesMax = computed(() => {
  const series = data.value?.plus_ones ?? []
  return Math.max(1, ...series.map((p) => p.count))
})

const ttrMax = computed(() => {
  const series = data.value?.time_to_respond ?? []
  return Math.max(1, ...series.map((p) => p.count))
})

const funnelPct = computed(() => {
  const f = data.value?.funnel
  if (!f || f.invited === 0) return { opened: 0, responded: 0 }
  return {
    opened: Math.round((f.opened / f.invited) * 100),
    responded: Math.round((f.responded / f.invited) * 100),
  }
})

const responseRateLineD = computed(() => {
  const series = data.value?.response_rate ?? []
  if (series.length === 0) return ''
  const w = 600
  const h = 80
  const max = responseRateMax.value
  const step = w / Math.max(1, series.length - 1)
  return series
    .map((p, i) => {
      const x = i * step
      const y = h - (p.count / max) * h
      return `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`
    })
    .join(' ')
})

function exportCSV() {
  // Issue a fresh ws-ticket-style download. Browsers preserve the
  // Authorization header on <a download> if we set it via fetch, so we
  // use fetch + blob + anchor.
  const url = `${config.public.apiBase}/events/${props.eventId}/analytics/export.csv`
  fetch(url, {
    headers: auth.liveAccessToken() ? { Authorization: `Bearer ${auth.liveAccessToken()}` } : {},
    credentials: 'include',
  })
    .then((res) => {
      if (!res.ok) throw new Error(`HTTP ${res.status}`)
      return res.blob()
    })
    .then((blob) => {
      const a = document.createElement('a')
      a.href = URL.createObjectURL(blob)
      a.download = 'analytics.csv'
      a.click()
      setTimeout(() => URL.revokeObjectURL(a.href), 1000)
    })
    .catch((e) => {
      error.value = 'Could not export: ' + String(e)
    })
}

function fmtDate(iso?: string | null) {
  if (!iso) return ''
  try { return new Date(iso).toLocaleDateString() } catch { return iso }
}
</script>

<template>
  <section class="card">
    <header class="mb-3 flex items-center justify-between">
      <h2 class="text-lg font-semibold">Analytics</h2>
      <button class="btn-ghost text-sm" :disabled="!data" @click="exportCSV">Export CSV</button>
    </header>

    <p v-if="loading" class="text-sm text-zinc-500">Loading analytics…</p>
    <p v-else-if="error" class="text-sm text-red-400">{{ error }}</p>

    <div v-else-if="data" class="space-y-6">
      <!-- Overview tiles -->
      <div class="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-6">
        <div class="rounded-md border border-zinc-800 bg-zinc-950 p-3">
          <p class="text-xs uppercase tracking-wider text-zinc-500">Invited</p>
          <p class="mt-1 text-2xl font-semibold tabular-nums">{{ data.overview.invited }}</p>
        </div>
        <div class="rounded-md border border-brand-900/60 bg-brand-950/20 p-3">
          <p class="text-xs uppercase tracking-wider text-brand-400">Attending</p>
          <p class="mt-1 text-2xl font-semibold tabular-nums text-brand-200">{{ data.overview.attending }}</p>
        </div>
        <div class="rounded-md border border-zinc-800 bg-zinc-950 p-3">
          <p class="text-xs uppercase tracking-wider text-zinc-500">Declined</p>
          <p class="mt-1 text-2xl font-semibold tabular-nums">{{ data.overview.declined }}</p>
        </div>
        <div class="rounded-md border border-zinc-800 bg-zinc-950 p-3">
          <p class="text-xs uppercase tracking-wider text-zinc-500">Maybe</p>
          <p class="mt-1 text-2xl font-semibold tabular-nums">{{ data.overview.maybe }}</p>
        </div>
        <div class="rounded-md border border-zinc-800 bg-zinc-950 p-3">
          <p class="text-xs uppercase tracking-wider text-zinc-500">Pending</p>
          <p class="mt-1 text-2xl font-semibold tabular-nums">{{ data.overview.pending }}</p>
        </div>
        <div class="rounded-md border border-zinc-800 bg-zinc-950 p-3">
          <p class="text-xs uppercase tracking-wider text-zinc-500">Plus-ones</p>
          <p class="mt-1 text-2xl font-semibold tabular-nums">+{{ data.overview.plus_ones_total }}</p>
        </div>
      </div>

      <!-- Response rate over time -->
      <div>
        <p class="mb-2 text-xs font-medium uppercase tracking-wider text-zinc-500">Responses, last 30 days</p>
        <svg viewBox="0 0 600 80" preserveAspectRatio="none" class="h-20 w-full">
          <path :d="responseRateLineD" fill="none" stroke="#22c55e" stroke-width="1.5" />
        </svg>
      </div>

      <!-- Funnel -->
      <div>
        <p class="mb-2 text-xs font-medium uppercase tracking-wider text-zinc-500">Funnel</p>
        <div class="space-y-1.5">
          <div class="flex items-center gap-3">
            <span class="w-24 shrink-0 text-xs text-zinc-400">Invited</span>
            <div class="h-6 flex-1 overflow-hidden rounded bg-zinc-900">
              <div class="h-full rounded bg-brand-500" :style="{ width: '100%' }"></div>
            </div>
            <span class="w-12 shrink-0 text-right text-xs tabular-nums text-zinc-300">{{ data.funnel.invited }}</span>
          </div>
          <div class="flex items-center gap-3">
            <span class="w-24 shrink-0 text-xs text-zinc-400">Opened</span>
            <div class="h-6 flex-1 overflow-hidden rounded bg-zinc-900">
              <div class="h-full rounded bg-brand-400" :style="{ width: funnelPct.opened + '%' }"></div>
            </div>
            <span class="w-12 shrink-0 text-right text-xs tabular-nums text-zinc-300">{{ data.funnel.opened }}</span>
          </div>
          <div class="flex items-center gap-3">
            <span class="w-24 shrink-0 text-xs text-zinc-400">Responded</span>
            <div class="h-6 flex-1 overflow-hidden rounded bg-zinc-900">
              <div class="h-full rounded bg-brand-300" :style="{ width: funnelPct.responded + '%' }"></div>
            </div>
            <span class="w-12 shrink-0 text-right text-xs tabular-nums text-zinc-300">{{ data.funnel.responded }}</span>
          </div>
        </div>
      </div>

      <!-- Time-to-respond + plus-ones side by side -->
      <div class="grid grid-cols-1 gap-6 md:grid-cols-2">
        <div>
          <p class="mb-2 text-xs font-medium uppercase tracking-wider text-zinc-500">Time to respond</p>
          <div class="space-y-1.5">
            <div v-for="b in data.time_to_respond" :key="b.label" class="flex items-center gap-3">
              <span class="w-12 shrink-0 text-xs text-zinc-400">{{ b.label }}</span>
              <div class="h-4 flex-1 overflow-hidden rounded bg-zinc-900">
                <div class="h-full rounded bg-brand-500" :style="{ width: ((b.count / ttrMax) * 100) + '%' }"></div>
              </div>
              <span class="w-8 shrink-0 text-right text-xs tabular-nums text-zinc-300">{{ b.count }}</span>
            </div>
          </div>
        </div>

        <div>
          <p class="mb-2 text-xs font-medium uppercase tracking-wider text-zinc-500">Plus-ones (attending)</p>
          <div class="space-y-1.5">
            <div v-for="b in data.plus_ones" :key="b.label" class="flex items-center gap-3">
              <span class="w-12 shrink-0 text-xs text-zinc-400">{{ b.label }}</span>
              <div class="h-4 flex-1 overflow-hidden rounded bg-zinc-900">
                <div class="h-full rounded bg-brand-500" :style="{ width: ((b.count / plusOnesMax) * 100) + '%' }"></div>
              </div>
              <span class="w-8 shrink-0 text-right text-xs tabular-nums text-zinc-300">{{ b.count }}</span>
            </div>
          </div>
        </div>
      </div>

      <!-- Stale guests -->
      <div>
        <p class="mb-2 text-xs font-medium uppercase tracking-wider text-zinc-500">
          Haven't responded yet ({{ data.stale_guests.length }})
        </p>
        <p v-if="data.stale_guests.length === 0" class="text-sm text-zinc-500">
          Everyone you've invited has replied. 🎉
        </p>
        <ul v-else class="space-y-1.5">
          <li
            v-for="g in data.stale_guests.slice(0, 10)"
            :key="g.guest_id"
            class="flex items-center justify-between rounded-md border border-zinc-800 bg-zinc-950 px-3 py-2 text-sm"
          >
            <div class="min-w-0 flex-1">
              <div class="truncate font-medium text-zinc-100">{{ g.name }}</div>
              <div class="truncate text-xs text-zinc-500">
                {{ g.email || 'no email' }} · invited {{ fmtDate(g.invited_at) }}
                <span v-if="g.has_opened" class="ml-1 text-amber-400">opened</span>
              </div>
            </div>
          </li>
        </ul>
        <p v-if="data.stale_guests.length > 10" class="mt-2 text-xs text-zinc-500">
          and {{ data.stale_guests.length - 10 }} more — export the CSV for the full list.
        </p>
      </div>
    </div>
  </section>
</template>
