<template>
  <div class="p-4 sm:p-6 max-w-5xl mx-auto">

    <!-- Header -->
    <div class="mb-6">
      <h1 class="text-text-primary text-xl font-semibold mb-1">Received Bundles</h1>
      <p class="text-text-dim text-sm">Labeled incident bundles sent from remote Turnstone instances. Use these to build detection signatures.</p>
    </div>

    <div v-if="loading" class="text-text-dim py-8 text-center text-sm">Loading…</div>

    <div v-else-if="bundles.length === 0" class="rounded border border-surface-border bg-surface-raised p-8 text-center">
      <p class="text-text-muted text-base mb-1">No bundles received yet.</p>
      <p class="text-text-dim text-sm">Bundles arrive when a remote Turnstone instance sends a labeled incident.</p>
    </div>

    <div v-else class="space-y-3">
      <div
        v-for="b in bundles"
        :key="b.id"
        class="rounded border bg-surface-raised overflow-hidden"
        :class="selected?.id === b.id ? 'border-accent' : 'border-surface-border'"
      >
        <!-- Bundle header row -->
        <div
          class="flex flex-wrap items-center gap-2 sm:gap-3 px-3 sm:px-4 py-3 cursor-pointer hover:bg-surface transition-colors"
          @click="toggleBundle(b)"
        >
          <span class="font-mono text-xs text-accent bg-surface px-1.5 py-0.5 rounded border border-surface-border shrink-0">
            {{ b.issue_type || 'untyped' }}
          </span>
          <span class="text-text-primary text-sm flex-1 min-w-0 truncate">{{ b.label }}</span>
          <span class="text-text-dim text-xs shrink-0 hidden sm:inline">{{ b.source_host }}</span>
          <span class="px-2 py-0.5 rounded text-xs font-medium border shrink-0" :style="severityStyle(b.severity)">{{ b.severity }}</span>
          <span class="text-text-dim text-xs shrink-0">{{ b.entry_count }} entries</span>
          <span class="text-text-dim text-xs shrink-0 hidden sm:inline">{{ formatTs(b.bundled_at) }}</span>
          <span class="text-text-dim text-xs shrink-0">{{ selected?.id === b.id ? '▲' : '▼' }}</span>
        </div>

        <!-- Expanded entries -->
        <div v-if="selected?.id === b.id" class="border-t border-surface-border">
          <div v-if="expandLoading" class="text-text-dim text-sm px-4 py-4">Loading entries…</div>
          <div v-else-if="expandedEntries.length === 0" class="text-text-dim text-sm px-4 py-4">No entries in bundle.</div>
          <div v-else class="p-4 space-y-1 max-h-[32rem] overflow-y-auto">
            <div class="flex items-center gap-2 mb-3">
              <p class="text-text-dim text-xs">{{ expandedEntries.length }} log entries</p>
              <button
                @click="exportBundle(b)"
                class="ml-auto text-xs px-2 py-1 rounded border border-surface-border text-text-muted hover:text-accent hover:border-accent transition-colors"
              >
                Export JSON
              </button>
            </div>
            <div
              v-for="entry in expandedEntries"
              :key="entry.entry_id"
              class="font-mono text-xs py-1 px-2 rounded bg-surface border border-surface-border"
            >
              <span class="text-text-dim mr-2">{{ shortTs(entry.timestamp_iso) }}</span>
              <span :class="['mr-2', severityClass(entry.severity)]">{{ entry.severity || '?' }}</span>
              <span class="text-text-muted">{{ lastPart(entry.source_id) }}</span>
              <span class="text-text-dim mx-1">|</span>
              <span class="text-text-primary">{{ entry.text.slice(0, 200) }}</span>
            </div>
          </div>
        </div>
      </div>
    </div>

  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'

const BASE = import.meta.env.BASE_URL.replace(/\/$/, '')

interface BundleSummary {
  id: string
  source_host: string
  issue_type: string
  label: string
  severity: string
  started_at: string | null
  bundled_at: string
  entry_count: number
  bundle_json: string
}

interface LogEntry {
  entry_id: string
  source_id: string
  timestamp_iso: string | null
  severity: string | null
  text: string
  matched_patterns: string[]
}

const bundles       = ref<BundleSummary[]>([])
const loading       = ref(true)
const selected      = ref<BundleSummary | null>(null)
const expandedEntries = ref<LogEntry[]>([])
const expandLoading = ref(false)

onMounted(async () => {
  try {
    const res = await fetch(`${BASE}/api/bundles`)
    if (res.ok) bundles.value = (await res.json()).bundles
  } finally {
    loading.value = false
  }
})

async function toggleBundle(b: BundleSummary) {
  if (selected.value?.id === b.id) {
    selected.value = null
    expandedEntries.value = []
    return
  }
  selected.value = b
  expandedEntries.value = []
  expandLoading.value = true
  try {
    // bundle_json is stored inline — parse it directly, no round-trip needed
    const parsed = JSON.parse(b.bundle_json)
    expandedEntries.value = parsed.log_entries ?? []
  } catch {
    expandLoading.value = false
  } finally {
    expandLoading.value = false
  }
}

function exportBundle(b: BundleSummary) {
  const blob = new Blob([b.bundle_json], { type: 'application/json' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = `bundle-${b.issue_type || 'untyped'}-${b.id.slice(0, 8)}.json`
  a.click()
  URL.revokeObjectURL(url)
}

function severityStyle(sev: string): Record<string, string> {
  const k = sev?.toLowerCase() ?? 'low'
  const known = ['low', 'medium', 'high', 'critical']
  const key = known.includes(k) ? k : 'low'
  return {
    backgroundColor: `var(--badge-${key}-bg)`,
    color:           `var(--badge-${key}-text)`,
    borderColor:     `var(--badge-${key}-text)`,
  }
}

function severityClass(sev: string | null): string {
  return {
    ERROR:    'text-sev-error',
    CRITICAL: 'text-sev-critical',
    WARN:     'text-sev-warn',
    WARNING:  'text-sev-warn',
    INFO:     'text-sev-info',
    DEBUG:    'text-text-dim',
  }[sev?.toUpperCase() ?? ''] ?? 'text-text-dim'
}

function lastPart(sourceId: string): string {
  return sourceId.split(':').pop() ?? sourceId
}

function formatTs(iso: string | null): string {
  if (!iso) return '—'
  try {
    return new Date(iso).toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })
  } catch { return iso }
}

function shortTs(iso: string | null): string {
  if (!iso) return '?'
  try {
    return new Date(iso).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' })
  } catch { return iso }
}
</script>
