<script setup lang="ts">
import { computed, ref } from 'vue'
import { AlertTriangle, AlertCircle, Info, ArrowLeft, Clock, ServerCog } from '@lucide/vue'
import { useIncidentQuery, useIncidentsQuery } from '../api/incidents'
import { renderMarkdown } from '../utils/markdown'
import { RouterLink } from 'vue-router'
import { useOpenClawOverviewQuery } from '../api/openclawRuntime'
import AsyncStatePanel from '../components/mission-control/AsyncStatePanel.vue'

const overviewQuery = useOpenClawOverviewQuery()
const incidentsQuery = useIncidentsQuery()

// State
const incidents = computed(() => incidentsQuery.data.value ?? [])
const loading = computed(() => incidentsQuery.isPending.value)
const selectedIncidentName = ref('')
const incidentQuery = useIncidentQuery(selectedIncidentName)
const selectedIncident = computed(() =>
  selectedIncidentName.value ? incidentQuery.data.value ?? null : null,
)
const selectedIncidentSummary = computed(() =>
  incidents.value.find(incident => incident.name === selectedIncidentName.value) ?? null,
)
const contentLoading = computed(() => incidentQuery.isFetching.value)
const listProblem = computed(() => incidentsQuery.error.value)
const contentProblem = computed(() => incidentQuery.error.value)

// Sorted incidents (newest first by date)
const sortedIncidents = computed(() => {
  return [...incidents.value].sort((a, b) => {
    if (a.date && b.date) return b.date.localeCompare(a.date)
    if (a.date) return -1
    if (b.date) return 1
    return a.name.localeCompare(b.name)
  })
})
const runtimeFailures = computed(() =>
  (overviewQuery.data.value?.tasks.items ?? [])
    .filter(task => ['failed', 'timed_out', 'lost'].includes(task.status.toLocaleLowerCase()))
    .sort((left, right) =>
      new Date(right.finishedAt || right.updatedAt || 0).getTime()
      - new Date(left.finishedAt || left.updatedAt || 0).getTime(),
    ),
)

// Severity badge mapping
function severityClass(s: string): string {
  const lower = s.toLowerCase()
  if (lower.includes('critical')) return 'sev-critical'
  if (lower.includes('major')) return 'sev-major'
  if (lower.includes('minor')) return 'sev-minor'
  return 'sev-unknown'
}

function severityIcon(s: string) {
  const lower = s.toLowerCase()
  if (lower.includes('critical')) return AlertCircle
  if (lower.includes('major')) return AlertTriangle
  return Info
}

function selectIncident(name: string) {
  selectedIncidentName.value = name
}

function goBack() {
  selectedIncidentName.value = ''
}

function retryList() {
  void incidentsQuery.refetch()
}

function retryContent() {
  void incidentQuery.refetch()
}

function retryRuntime() {
  void overviewQuery.refetch()
}

function formatDate(dateStr: string): string {
  return new Date(dateStr + 'T00:00:00').toLocaleDateString('de-DE', {
    year: 'numeric', month: 'short', day: 'numeric',
  })
}

function formatSize(bytes: number | string): string {
  const numericBytes = Number(bytes)
  if (!Number.isFinite(numericBytes)) return String(bytes)
  if (numericBytes < 1024) return `${numericBytes} B`
  if (numericBytes < 1024 * 1024) return `${(numericBytes / 1024).toFixed(1)} KB`
  return `${(numericBytes / (1024 * 1024)).toFixed(1)} MB`
}

</script>

<template>
  <div class="incidents-page nexus-page">
  <div class="page-heading">
    <div>
      <span class="eyebrow">OPERATIONS</span>
      <h1>Incidents</h1>
      <p>Post-mortem reports and operational incidents across Noveria.</p>
    </div>
  </div>

  <section v-if="runtimeFailures.length" class="runtime-incidents nexus-panel" aria-labelledby="runtime-incidents-title">
    <header>
      <div>
        <span class="eyebrow">LIVE OPENCLAW FAILURES</span>
        <h2 id="runtime-incidents-title">{{ runtimeFailures.length }} runtime tasks need attention</h2>
        <p>These are current gateway task failures, separate from durable post-mortem reports.</p>
      </div>
      <RouterLink class="nexus-button nexus-button--primary" to="/runs">
        <ServerCog :size="14" />
        Open Run Control
      </RouterLink>
    </header>
    <div class="runtime-failure-list">
      <article v-for="task in runtimeFailures.slice(0, 4)" :key="task.id">
        <AlertCircle :size="16" aria-hidden="true" />
        <div>
          <strong>{{ task.title }}</strong>
          <p>{{ task.error || task.summary || 'OpenClaw reported a failed task without an error summary.' }}</p>
          <code>{{ task.agentId || 'unassigned' }} · {{ task.status }} · {{ task.id }}</code>
        </div>
      </article>
    </div>
  </section>

  <AsyncStatePanel
    v-else-if="overviewQuery.error.value"
    state="partial"
    title="Live-Incidents nicht vollständig"
    message="Post-Mortems bleiben verfügbar; aktuelle OpenClaw-Fehler konnten nicht synchronisiert werden."
    :problem="overviewQuery.error.value"
    action-label="Runtime aktualisieren"
    compact
    @action="retryRuntime"
  />

  <div class="incident-layout">
    <!-- Left column: incident list -->
    <aside class="incident-sidebar">
      <AsyncStatePanel
        v-if="loading && !incidents.length"
        state="loading"
        title="Incidents werden geladen"
        compact
      />
      <AsyncStatePanel
        v-else-if="listProblem && !incidents.length"
        state="error"
        title="Incident-Berichte nicht verfügbar"
        :problem="listProblem"
        compact
        @action="retryList"
      />
      <template v-else-if="sortedIncidents.length">
        <AsyncStatePanel
          v-if="listProblem"
          state="stale"
          title="Incident-Liste möglicherweise veraltet"
          :problem="listProblem"
          action-label="Aktualisieren"
          compact
          @action="retryList"
        />
        <div class="incident-list-header">{{ sortedIncidents.length }} reports</div>
        <button
          v-for="inc in sortedIncidents"
          :key="inc.name"
          type="button"
          :class="['incident-file-item', { active: selectedIncidentName === inc.name }]"
          :aria-current="selectedIncidentName === inc.name ? 'true' : undefined"
          @click="selectIncident(inc.name)"
        >
          <div class="incident-file-icon" :class="severityClass(inc.severity)">
            <component :is="severityIcon(inc.severity)" :size="14" />
          </div>
          <div class="incident-file-info">
            <strong>{{ inc.title }}</strong>
            <span class="incident-file-meta">
              <Clock :size="10" />
              {{ inc.date ? formatDate(inc.date) : 'Unknown date' }}
              <span :class="['severity-badge', severityClass(inc.severity)]">{{ inc.severity }}</span>
            </span>
            <span class="incident-file-excerpt">{{ inc.excerpt }}</span>
          </div>
        </button>
      </template>
      <AsyncStatePanel
        v-else
        state="empty"
        title="Keine Incidents erfasst"
        message="Es liegen weder auswählbare Post-Mortems noch bestätigte Incident-Berichte vor."
        compact
      />
    </aside>

    <!-- Right column: detail view -->
    <main class="incident-content">
      <AsyncStatePanel
        v-if="contentLoading && !selectedIncident"
        state="loading"
        title="Incident wird geladen"
      />
      <AsyncStatePanel
        v-else-if="contentProblem && !selectedIncident"
        state="error"
        title="Incident nicht verfügbar"
        :problem="contentProblem"
        @action="retryContent"
      />
      <template v-else-if="selectedIncident">
        <AsyncStatePanel
          v-if="contentProblem"
          state="stale"
          title="Angezeigter Incident ist möglicherweise veraltet"
          :problem="contentProblem"
          action-label="Aktualisieren"
          compact
          @action="retryContent"
        />
        <header class="incident-content-header">
          <button type="button" class="incident-back-btn" @click="goBack">
            <ArrowLeft :size="14" />
            Back
          </button>
          <div>
            <div class="incident-content-title-row">
              <strong>{{ selectedIncident.title }}</strong>
              <span
                v-if="selectedIncidentSummary"
                :class="['severity-badge', severityClass(selectedIncidentSummary.severity)]"
              >
                {{ selectedIncidentSummary.severity }}
              </span>
            </div>
            <span class="incident-content-meta">
              <Clock :size="10" />
              {{ selectedIncident.date ? formatDate(selectedIncident.date) : 'Unknown date' }}
              · {{ formatSize(selectedIncident.size) }}
            </span>
            <span class="source-context">
              Agent
              <RouterLink :to="{ name: 'AgentDetail', params: { id: selectedIncident.sourceAgentId } }">
                {{ selectedIncident.sourceAgentId }}
              </RouterLink>
              · <code>{{ selectedIncident.workspacePath }}</code>
            </span>
          </div>
        </header>
        <article
          class="incident-rendered"
          v-html="renderMarkdown(selectedIncident.content)"
        ></article>
      </template>
      <template v-else>
        <div class="incident-empty-state">
          <AlertTriangle :size="28" />
          <h3>Select an incident report</h3>
          <p>Choose a report from the list to view its post-mortem details.</p>
        </div>
      </template>
    </main>
  </div>
  </div>
</template>

<style scoped>
.runtime-incidents {
  display: grid;
  gap: 13px;
  padding: 16px;
  border-color: var(--status-block-line);
  background: linear-gradient(135deg, var(--status-block-bg), var(--glass));
}

.runtime-incidents > header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
}

.runtime-incidents h2 {
  margin: 3px 0 5px;
  font-size: 16px;
}

.runtime-incidents header p {
  margin: 0;
  color: var(--tx-2);
  line-height: 1.5;
}

.runtime-failure-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}

.runtime-failure-list article {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 9px;
  padding: 11px;
  border: 1px solid var(--status-block-line);
  border-radius: var(--r-sm);
  background: var(--accent-wash);
  color: var(--st-block);
}

.runtime-failure-list article div {
  display: grid;
  gap: 4px;
}

.runtime-failure-list strong {
  color: var(--tx);
}

.runtime-failure-list p {
  margin: 0;
  color: var(--tx-2);
  line-height: 1.45;
}

.runtime-failure-list code {
  overflow: hidden;
  color: var(--tx-3);
  font-family: var(--font-mono-v2);
  font-size: 11px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.incident-layout {
  display: grid;
  grid-template-columns: 360px 1fr;
  gap: 12px;
  min-height: 480px;
}

@media (max-width: 760px) {
  .runtime-incidents > header {
    flex-direction: column;
  }

  .runtime-failure-list {
    grid-template-columns: 1fr;
  }
}
.incident-sidebar {
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--panel);
  padding: 8px;
  max-height: 640px;
  overflow-y: auto;
}
.incident-list-header {
  font-size: 9px;
  font-weight: 700;
  color: var(--tx-3);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  padding: 10px 8px 6px;
}
.incident-file-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  padding: 10px;
  border: none;
  border-radius: 7px;
  background: transparent;
  color: var(--tx);
  text-align: left;
  cursor: pointer;
  font: inherit;
}
.incident-file-item:hover,
.incident-file-item.active {
  background: var(--accent-soft);
}
.incident-file-icon {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border-radius: 6px;
}
.incident-file-icon.sev-critical {
  color: var(--st-review);
  background: color-mix(in srgb, var(--st-review) 12%, transparent);
}
.incident-file-icon.sev-major {
  color: var(--st-review);
  background: color-mix(in srgb, var(--st-review) 12%, transparent);
}
.incident-file-icon.sev-minor {
  color: var(--st-queue);
  background: color-mix(in srgb, var(--st-queue) 12%, transparent);
}
.incident-file-icon.sev-unknown {
  color: var(--tx-3);
  background: color-mix(in srgb, var(--tx-3) 12%, transparent);
}
.incident-file-info strong {
  display: block;
  font-size: 11px;
  margin-bottom: 3px;
  word-break: break-word;
}
.incident-file-meta {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 9px;
  color: var(--tx-3);
  margin-bottom: 4px;
}
.incident-file-excerpt {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 9px;
  color: var(--tx-3);
  line-height: 1.5;
}
.severity-badge {
  font-size: 8px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 2px 6px;
  border-radius: 4px;
}
.severity-badge.sev-critical {
  background: color-mix(in srgb, var(--st-review) 15%, transparent);
  color: var(--st-review);
}
.severity-badge.sev-major {
  background: color-mix(in srgb, var(--st-review) 15%, transparent);
  color: var(--st-review);
}
.severity-badge.sev-minor {
  background: color-mix(in srgb, var(--st-queue) 15%, transparent);
  color: var(--st-queue);
}
.severity-badge.sev-unknown {
  background: color-mix(in srgb, var(--tx-3) 15%, transparent);
  color: var(--tx-3);
}
.incident-content {
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--panel);
  padding: 24px;
  min-height: 480px;
  overflow-y: auto;
}
.incident-content-header {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 20px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--line);
}
.incident-content-title-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 3px;
}
.incident-content-title-row strong {
  font-size: 13px;
}
.incident-content-meta {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 9px;
  color: var(--tx-3);
}
.source-context {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 5px;
  color: var(--tx-3);
  font-family: var(--font-mono-v2);
  font-size: 10px;
}
.source-context a {
  color: var(--a-blue);
}
.source-context code {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.incident-back-btn {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 5px 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: transparent;
  color: var(--tx-3);
  font-size: 10px;
  cursor: pointer;
  flex-shrink: 0;
}
.incident-back-btn:hover {
  color: var(--tx);
  background: var(--accent-soft);
}
.incident-status {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 32px;
  color: var(--tx-3);
  font-size: 11px;
}
.incident-status.error {
  color: var(--st-block);
}
.incident-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  min-height: 360px;
  color: var(--tx-3);
}
.incident-empty-state h3 {
  margin: 12px 0 6px;
  font-size: 14px;
  color: var(--tx-2);
}
.incident-empty-state p {
  margin: 0;
  font-size: 10px;
  color: var(--tx-3);
}
.incident-rendered {
  font-size: 12px;
  line-height: 1.7;
  color: var(--tx);
}
.incident-rendered :deep(h1),
.incident-rendered :deep(h2),
.incident-rendered :deep(h3) {
  color: var(--tx);
  margin: 1.2em 0 0.5em;
}
.incident-rendered :deep(h1) { font-size: 1.3rem; }
.incident-rendered :deep(h2) { font-size: 1.1rem; }
.incident-rendered :deep(h3) { font-size: 1rem; }
.incident-rendered :deep(p) { margin: 0.6em 0; }
.incident-rendered :deep(code) {
  padding: 2px 5px;
  background: color-mix(in srgb, var(--a-mid) 8%, transparent);
  border-radius: 4px;
  font-size: 11px;
}
.incident-rendered :deep(pre) {
  padding: 12px;
  border-radius: 8px;
  background: var(--space-1);
  border: 1px solid var(--nx-line);
  overflow-x: auto;
}
.incident-rendered :deep(pre code) {
  background: none;
  padding: 0;
}
.incident-rendered :deep(a) {
  color: var(--tx-2);
  text-decoration: none;
}
.incident-rendered :deep(a:hover) {
  text-decoration: underline;
}
.incident-rendered :deep(ul) {
  padding-left: 20px;
}
.incident-rendered :deep(li) {
  margin: 0.3em 0;
}
.incident-rendered :deep(hr) {
  border: none;
  border-top: 1px solid var(--nx-line);
  margin: 1.2em 0;
}
.incident-rendered :deep(strong) {
  color: var(--tx);
}
.spin {
  animation: spin 1s linear infinite;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}

@media (max-width: 900px) {
  .incident-layout {
    grid-template-columns: 1fr;
  }
  .incident-sidebar {
    max-height: 280px;
  }
}
</style>
