<template>
  <div>
    <!-- Input row -->
    <div class="flex gap-3 mb-6">
      <label for="qc-query" class="sr-only">Describe the symptom or issue</label>
      <input
        id="qc-query"
        v-model="query"
        type="text"
        placeholder='e.g. "plex stopped playing audio around 2pm"'
        class="flex-1 bg-surface-raised border border-surface-border rounded px-4 py-2.5 text-sm text-text-primary placeholder-text-dim focus:outline-none focus:border-accent transition-colors"
        @keydown.enter="run()"
      />
      <button
        :disabled="loading || (!query.trim() && !sourceScope)"
        @click="run()"
        class="px-4 sm:px-6 py-2.5 rounded bg-accent text-white text-sm font-semibold hover:bg-blue-400 transition-colors disabled:opacity-50 shrink-0"
      >
        <span v-if="loading">Searching…</span>
        <span v-else>Search logs</span>
      </button>
    </div>

    <!-- Pipeline status -->
    <div aria-live="polite" aria-atomic="true">
      <div
        v-if="loading && statusMsg"
        class="flex items-center gap-2 mb-3 text-xs text-text-dim"
      >
        <span class="inline-block w-3 h-3 rounded-full border-2 border-accent border-t-transparent animate-spin motion-reduce:animate-none" aria-hidden="true" />
        <span>{{ statusMsg }}</span>
      </div>
    </div>

    <!-- Source scope badge -->
    <div v-if="sourceScope || timeFrom" class="flex flex-wrap items-center gap-2 mb-4 text-xs">
      <template v-if="sourceScope">
        <span class="text-text-dim">Scoped to:</span>
        <span class="font-mono text-surface bg-accent rounded px-2 py-0.5">{{ sourceScope }}</span>
        <button
          @click="sourceScope = null"
          class="text-text-dim hover:text-text-primary"
          title="Clear scope"
          aria-label="Clear source scope filter"
        >✕</button>
      </template>
      <template v-if="timeFrom">
        <span class="text-text-dim ml-1">Window:</span>
        <span class="font-mono text-surface bg-accent/80 rounded px-2 py-0.5">
          {{ _fmtTs(timeFrom) }} → {{ timeTo ? _fmtTs(timeTo) : 'now' }}
        </span>
        <button
          @click="timeFrom = null; timeTo = null"
          class="text-text-dim hover:text-text-primary"
          title="Clear time window"
          aria-label="Clear time window filter"
        >✕</button>
      </template>
    </div>

    <!-- Error -->
    <div v-if="error" role="alert" class="mb-4 p-3 rounded bg-red-900/30 border border-red-700/40 text-sev-error text-sm">
      {{ error }}
    </div>

    <!-- Summary header -->
    <div v-if="summary" class="mb-4 rounded border border-surface-border bg-surface-raised p-4">
      <div class="flex flex-wrap gap-x-6 gap-y-1 text-xs text-text-dim">
        <span class="text-text-muted font-medium">
          {{ severityFilter ? filteredEntries.length + ' of ' : '' }}{{ summary.total }} entr{{ summary.total !== 1 ? 'ies' : 'y' }}
        </span>
        <span v-if="summary.window_start">
          {{ fmtTs(summary.window_start) }} → {{ fmtTs(summary.window_end) }}
        </span>
        <span v-if="!summary.time_detected" class="italic">(last 60 min — no time detected)</span>
      </div>
      <!-- Severity filter pills -->
      <div class="flex flex-wrap gap-2 mt-2">
        <button
          v-for="(count, sev) in nonZeroSeverity"
          :key="String(sev)"
          @click="severityFilter = severityFilter === String(sev) ? null : String(sev)"
          :aria-pressed="severityFilter === String(sev)"
          :class="[
            'px-2 py-0.5 rounded text-xs font-medium border transition-colors',
            severityFilter === String(sev)
              ? sevActivePillClass(String(sev))
              : 'border-surface-border text-text-dim hover:border-current ' + sevClass(String(sev))
          ]"
        >{{ count }} {{ sev }}</button>
      </div>
      <div class="flex flex-wrap gap-x-4 gap-y-1 text-xs text-text-dim mt-2">
        <span v-for="(count, src) in summary.by_source" :key="String(src)">
          {{ String(src).split(':').pop() }} ({{ count }})
        </span>
      </div>
    </div>

    <!-- LLM reasoning card -->
    <div
      v-if="reasoning"
      class="mb-4 rounded-r border-l-4 border-accent bg-surface-raised p-4"
    >
      <div class="flex items-center gap-2 mb-2 text-xs text-accent font-semibold uppercase tracking-wide">
        <span aria-hidden="true">⚡</span>
        <span>Diagnosis</span>
        <span class="ml-auto text-text-dim font-normal normal-case tracking-normal capitalize">{{ techLevel }}</span>
      </div>
      <p class="text-sm text-text-primary leading-relaxed whitespace-pre-wrap">{{ reasoning }}</p>
    </div>

    <!-- Log stream -->
    <div v-if="filteredEntries.length" class="rounded border border-surface-border overflow-hidden mb-4">
      <LogEntryRow v-for="entry in filteredEntries" :key="entry.entry_id" :entry="entry" />
    </div>

    <!-- Zero state -->
    <div v-else-if="ranOnce && !loading" class="text-center text-text-dim py-12">
      <p v-if="severityFilter" class="mb-1">No {{ severityFilter }} entries in this result set.</p>
      <template v-else>
        <p class="mb-1">No log evidence found for "{{ lastQuery }}"</p>
        <p class="text-sm">Check the Sources tab to confirm data is gleaned, or try a broader description.</p>
      </template>
    </div>

    <!-- Save CTAs -->
    <div v-if="entries.length && !saved" class="mt-2 flex items-center gap-4">
      <button
        @click="saveQuick"
        :disabled="saving"
        class="px-4 py-2 bg-accent text-surface text-sm rounded font-medium hover:opacity-90 transition-opacity disabled:opacity-40"
      >
        {{ saving ? 'Saving…' : 'Save as incident' }}
      </button>
      <button
        v-if="!showDetails"
        @click="showDetails = true"
        class="text-text-dim hover:text-text-primary text-sm underline underline-offset-2"
      >
        add details…
      </button>
    </div>

    <!-- Inline details panel -->
    <div v-if="showDetails && !saved" class="mt-4 rounded border border-surface-border bg-surface-raised p-4 space-y-3">
      <div class="flex flex-wrap gap-3">
        <div>
          <label class="block text-xs text-text-dim mb-1">Severity</label>
          <select
            v-model="detailSeverity"
            class="bg-surface border border-surface-border rounded px-3 py-1.5 text-sm text-text-primary focus:outline-none focus:border-accent"
          >
            <option value="low">Low</option>
            <option value="medium">Medium</option>
            <option value="high">High</option>
            <option value="critical">Critical</option>
          </select>
        </div>
        <div class="flex-1 min-w-48">
          <label class="block text-xs text-text-dim mb-1">Notes <span class="text-text-dim">(optional)</span></label>
          <input
            v-model="detailNotes"
            type="text"
            placeholder="Any extra context…"
            class="w-full bg-surface border border-surface-border rounded px-3 py-1.5 text-sm text-text-primary placeholder-text-dim focus:outline-none focus:border-accent"
          />
        </div>
      </div>
      <div class="flex gap-3">
        <button
          @click="saveWithDetails"
          :disabled="saving"
          class="px-4 py-2 bg-accent text-surface text-sm rounded font-medium hover:opacity-90 transition-opacity disabled:opacity-40"
        >
          {{ saving ? 'Saving…' : 'Save' }}
        </button>
        <button @click="showDetails = false" class="text-text-dim hover:text-text-primary text-sm">Cancel</button>
      </div>
    </div>

    <!-- Saved confirmation -->
    <div v-if="saved" class="mt-2 text-sm text-green-400">
      Saved —
      <RouterLink to="/incidents" class="underline underline-offset-2 hover:text-green-300">view in Incidents</RouterLink>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, watch } from 'vue'
import { useRoute, RouterLink } from 'vue-router'
import LogEntryRow from '@/components/LogEntryRow.vue'
import type { LogEntry } from '@/stores/search'

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

interface Summary {
  total: number
  window_start: string | null
  window_end: string | null
  time_detected: boolean
  by_severity: Record<string, number>
  by_source: Record<string, number>
}

const query          = ref('')
const sourceScope    = ref<string | null>(null)
const timeFrom       = ref<string | null>(null)
const timeTo         = ref<string | null>(null)
const entries        = ref<LogEntry[]>([])
const summary        = ref<Summary | null>(null)
const reasoning      = ref<string | null>(null)
const techLevel      = ref<'homelab' | 'sysadmin' | 'executive'>('sysadmin')
const loading        = ref(false)
const statusMsg      = ref<string | null>(null)
const error          = ref<string | null>(null)
const ranOnce        = ref(false)
const lastQuery      = ref('')
const saved          = ref(false)
const saving         = ref(false)
const showDetails    = ref(false)
const detailSeverity = ref('medium')
const detailNotes    = ref('')
const severityFilter = ref<string | null>(null)
let   capturedSince: string | null = null
let   capturedUntil: string | null = null

function _fmtTs(iso: string): string {
  try {
    return new Date(iso).toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })
  } catch { return iso }
}

onMounted(async () => {
  const s = route.query.source
  if (typeof s === 'string' && s.trim()) sourceScope.value = s
  const f = route.query.from
  const t = route.query.to
  if (typeof f === 'string' && f) timeFrom.value = f
  if (typeof t === 'string' && t) timeTo.value = t
  const q = route.query.q
  if (typeof q === 'string' && q.trim()) {
    query.value = q
    run()
  } else if (sourceScope.value) {
    run()
  }
  try {
    const res = await fetch(`${BASE}/api/settings`)
    if (res.ok) {
      const prefs = await res.json()
      if (prefs.tech_level) techLevel.value = prefs.tech_level
    }
  } catch { /* non-critical — default stays */ }
})

watch(() => route.query.source, (newS) => {
  sourceScope.value = typeof newS === 'string' && newS.trim() ? newS : null
})

watch(() => route.query.q, (newQ) => {
  if (typeof newQ === 'string' && newQ.trim() && newQ !== lastQuery.value) {
    query.value = newQ
    run()
  }
})

async function run() {
  if (!query.value.trim() && !sourceScope.value) return
  loading.value    = true
  statusMsg.value  = 'Searching…'
  error.value      = null
  ranOnce.value    = true
  lastQuery.value  = query.value
  saved.value         = false
  showDetails.value   = false
  severityFilter.value = null
  entries.value    = []
  summary.value    = null
  reasoning.value  = null

  try {
    const res = await fetch(`${BASE}/api/diagnose/stream`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        query: query.value,
        source: sourceScope.value,
        since: timeFrom.value || undefined,
        until: timeTo.value   || undefined,
      }),
    })
    if (!res.ok) throw new Error(`API returned ${res.status}`)
    if (!res.body)  throw new Error('No response body')

    const reader  = res.body.getReader()
    const decoder = new TextDecoder()
    let   buf     = ''

    while (true) {
      const { done, value } = await reader.read()
      if (done) break
      buf += decoder.decode(value, { stream: true })
      // SSE events are separated by '\n\n'
      const parts = buf.split('\n\n')
      buf = parts.pop() ?? ''
      for (const part of parts) {
        const line = part.trim()
        if (!line.startsWith('data: ')) continue
        const evt = JSON.parse(line.slice(6))
        if (evt.type === 'status') {
          statusMsg.value = evt.message
        } else if (evt.type === 'summary') {
          summary.value  = evt.data
          capturedSince  = evt.data.window_start
          capturedUntil  = evt.data.window_end
        } else if (evt.type === 'entries') {
          entries.value  = evt.data
        } else if (evt.type === 'reasoning') {
          reasoning.value = evt.text
        } else if (evt.type === 'done') {
          statusMsg.value = null
        }
      }
    }
  } catch (e) {
    error.value = e instanceof Error ? e.message : String(e)
  } finally {
    loading.value   = false
    statusMsg.value = null
  }
}

async function saveQuick() {
  saving.value = true
  try { await postIncident('medium', '') }
  catch (e) { error.value = e instanceof Error ? e.message : 'Failed to save incident' }
  finally { saving.value = false }
}

async function saveWithDetails() {
  saving.value = true
  try { await postIncident(detailSeverity.value, detailNotes.value) }
  catch (e) { error.value = e instanceof Error ? e.message : 'Failed to save incident' }
  finally { saving.value = false }
}

async function postIncident(severity: string, notes: string) {
  const res = await fetch(`${BASE}/api/incidents`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      label:      lastQuery.value,
      started_at: capturedSince,
      ended_at:   capturedUntil,
      severity,
      notes,
    }),
  })
  if (!res.ok) throw new Error(await res.text())
  saved.value = true
  showDetails.value = false
}

const nonZeroSeverity = computed(() => {
  if (!summary.value) return {}
  return Object.fromEntries(
    Object.entries(summary.value.by_severity).filter(([, v]) => v > 0)
  )
})

const filteredEntries = computed(() =>
  severityFilter.value
    ? entries.value.filter(e => (e.severity ?? 'INFO').toUpperCase() === severityFilter.value)
    : entries.value
)

function sevClass(sev: string): string {
  return ({
    CRITICAL: 'text-sev-critical',
    ERROR:    'text-sev-error',
    WARN:     'text-sev-warn',
    INFO:     'text-sev-info',
  } as Record<string, string>)[sev] ?? 'text-text-dim'
}

function sevActivePillClass(sev: string): string {
  return ({
    CRITICAL: 'bg-sev-critical/20 border-sev-critical text-sev-critical',
    ERROR:    'bg-sev-error/20 border-sev-error text-sev-error',
    WARN:     'bg-sev-warn/20 border-sev-warn text-sev-warn',
    INFO:     'bg-sev-info/20 border-sev-info text-sev-info',
  } as Record<string, string>)[sev] ?? 'bg-surface-raised border-surface-border text-text-dim'
}

function fmtTs(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 }
}
</script>
