<script lang="ts">
  import { onMount, tick } from 'svelte'
  import uPlot from 'uplot'
  import 'uplot/dist/uPlot.min.css'
  import {
    fetchEntity,
    fetchGraph,
    fetchMetrics,
    fetchEntityEvents,
    fetchEntitySignals,
    fetchEntityExecutions,
    fetchEntityKnowledge,
    fetchChecksForTarget,
    patchCheck,
    type Entity,
    type Relationship,
    type MetricSeries,
    type Signal,
    type Execution,
    type KnowledgeHit,
    type Check
  } from '$lib/api'
  import { relativeTime } from '$lib/utils'
  import type { OikosEvent } from '$lib/stores/events'
  import * as Card from '$lib/components/ui/card'
  import { Badge } from '$lib/components/ui/badge'
  import { Skeleton } from '$lib/components/ui/skeleton'
  import { toast } from 'svelte-sonner'

  let { slug }: { slug: string } = $props()

  let entity = $state<Entity | null>(null)
  let relations = $state<Relationship[]>([])
  let metrics = $state<MetricSeries[]>([])
  let events = $state<OikosEvent[]>([])
  let signals = $state<Signal[]>([])
  let executions = $state<Execution[]>([])
  let knowledge = $state<KnowledgeHit[]>([])
  let checks = $state<Check[]>([])
  let loading = $state(true)
  let chartContainers: Record<string, HTMLDivElement> = {}

  async function load(s: string) {
    loading = true
    entity = await fetchEntity(s)
    if (!entity) {
      loading = false
      return
    }
    const [graphView, m, ev, sig, exec, kh, ch] = await Promise.all([
      fetchGraph({ root: entity.id, depth: 1 }),
      fetchMetrics(entity.id),
      fetchEntityEvents(entity.id),
      fetchEntitySignals(entity.id),
      fetchEntityExecutions(entity.id),
      fetchEntityKnowledge(entity.id),
      fetchChecksForTarget(entity.slug)
    ])
    relations = graphView?.edges ?? []
    metrics = m
    events = ev
    signals = sig
    executions = exec
    knowledge = kh
    checks = ch
    loading = false

    await tick()
    renderCharts()
  }

  onMount(() => {
    load(slug)
  })

  $effect(() => {
    if (slug) load(slug)
  })

  function renderCharts() {
    for (const series of metrics) {
      const el = chartContainers[series.metric]
      if (!el) continue
      el.innerHTML = ''
      const xs = series.samples.map((s) => new Date(s.ts).getTime() / 1000)
      const ys = series.samples.map((s) => s.value ?? s.avg ?? null)
      new uPlot(
        {
          width: el.clientWidth || 400,
          height: 160,
          series: [{}, { label: series.metric, stroke: '#58a6ff', width: 2 }],
          axes: [{ stroke: '#8b949e' }, { stroke: '#8b949e' }],
          scales: { x: { time: true } },
          legend: { show: false }
        },
        [xs, ys],
        el
      )
    }
  }

  function severityVariant(sev: string): 'default' | 'secondary' | 'destructive' {
    if (sev === 'critical') return 'destructive'
    if (sev === 'warning') return 'secondary'
    return 'default'
  }

  const healthDot: Record<string, string> = {
    healthy: 'bg-success',
    degraded: 'bg-warning',
    down: 'bg-destructive',
    stale: 'bg-warning/50',
    unknown: 'bg-muted-foreground/40'
  }

  async function toggleCheck(check: Check) {
    const updated = await patchCheck(check.id, check.version, { enabled: !check.enabled })
    if (updated) {
      checks = checks.map((c) => (c.id === check.id ? updated : c))
      toast.success(`${check.slug} ${updated.enabled ? 'enabled' : 'disabled'}`)
    } else {
      toast.error('Failed to update check')
    }
  }
</script>

<div class="@container flex h-full flex-col gap-4 overflow-y-auto p-4 md:p-6">
  {#if loading}
    <Skeleton class="h-8 w-48" />
    <div class="grid grid-cols-1 gap-4 @lg:grid-cols-2">
      <Skeleton class="h-40 w-full" />
      <Skeleton class="h-40 w-full" />
    </div>
  {:else if !entity}
    <p class="text-sm text-muted-foreground">Entity "{slug}" not found.</p>
  {:else}
    <div class="flex flex-wrap items-center gap-2">
      <h1 class="font-mono text-lg font-semibold">{entity.slug}</h1>
      <Badge variant="outline">{entity.type}</Badge>
      {#if entity.state}<Badge>{entity.state}</Badge>{/if}
      {#if entity.health}
        <span class="flex items-center gap-1.5 text-xs text-muted-foreground" title="{entity.health} — checked {relativeTime(entity.last_check_at)}">
          <span class="size-2 rounded-full {healthDot[entity.health] ?? healthDot.unknown}"></span>
          {entity.health} · checked {relativeTime(entity.last_check_at)}
        </span>
      {/if}
    </div>

    <Card.Root>
      <Card.Header>
        <Card.Title class="text-sm">Monitoring ({checks.length})</Card.Title>
      </Card.Header>
      <Card.Content class="flex flex-col gap-1.5">
        {#each checks as check (check.id)}
          <div class="flex items-center justify-between gap-2 rounded-md border px-2.5 py-1.5 text-xs">
            <div class="flex items-center gap-2">
              <Badge variant="outline" class="font-mono">{check.kind}</Badge>
              <span class="text-muted-foreground">every {check.interval_s}s</span>
            </div>
            <button
              type="button"
              class="cursor-pointer"
              onclick={() => toggleCheck(check)}
              title={check.enabled ? 'Click to disable' : 'Click to enable'}
            >
              <Badge variant={check.enabled ? 'default' : 'secondary'}>{check.enabled ? 'enabled' : 'disabled'}</Badge>
            </button>
          </div>
        {:else}
          <p class="text-xs text-muted-foreground">No checks configured for this entity.</p>
        {/each}
      </Card.Content>
    </Card.Root>

    <div class="grid grid-cols-1 gap-4 @2xl:grid-cols-2">
      <Card.Root>
        <Card.Header>
          <Card.Title class="text-sm">Attributes</Card.Title>
        </Card.Header>
        <Card.Content>
          {#if entity.attributes && Object.keys(entity.attributes).length}
            <dl class="flex flex-col gap-1.5 text-xs">
              {#each Object.entries(entity.attributes) as [key, value]}
                <div class="flex items-start justify-between gap-3 border-b pb-1.5 last:border-0">
                  <dt class="shrink-0 font-mono text-muted-foreground">{key}</dt>
                  <dd class="min-w-0 flex-1 truncate text-right">
                    {typeof value === 'object' ? JSON.stringify(value) : String(value)}
                  </dd>
                </div>
              {/each}
            </dl>
          {:else}
            <p class="text-xs text-muted-foreground">No attributes.</p>
          {/if}
        </Card.Content>
      </Card.Root>

      <Card.Root>
        <Card.Header>
          <Card.Title class="text-sm">Relations ({relations.length})</Card.Title>
        </Card.Header>
        <Card.Content class="flex flex-col gap-1">
          {#each relations as rel}
            <div class="flex items-center gap-1 font-mono text-xs">
              <span>{rel.source}</span>
              <span class="text-muted-foreground">—{rel.type}→</span>
              <span>{rel.target}</span>
            </div>
          {:else}
            <p class="text-xs text-muted-foreground">No direct relations.</p>
          {/each}
        </Card.Content>
      </Card.Root>
    </div>

    {#if metrics.length}
      <Card.Root>
        <Card.Header>
          <Card.Title class="text-sm">Metrics</Card.Title>
        </Card.Header>
        <Card.Content class="grid grid-cols-1 gap-4 @2xl:grid-cols-2">
          {#each metrics as series (series.metric)}
            <div>
              <p class="mb-1 text-xs text-muted-foreground">{series.metric} ({series.rollup})</p>
              <div bind:this={chartContainers[series.metric]}></div>
            </div>
          {/each}
        </Card.Content>
      </Card.Root>
    {/if}

    <div class="grid grid-cols-1 gap-4 @3xl:grid-cols-3">
      <Card.Root>
        <Card.Header>
          <Card.Title class="text-sm">Open signals</Card.Title>
        </Card.Header>
        <Card.Content class="flex flex-col gap-1">
          {#each signals as signal (signal.id)}
            <div class="flex items-center justify-between text-xs">
              <span>{signal.kind}</span>
              <Badge variant={severityVariant(signal.severity)}>{signal.severity}</Badge>
            </div>
          {:else}
            <p class="text-xs text-muted-foreground">None.</p>
          {/each}
        </Card.Content>
      </Card.Root>

      <Card.Root>
        <Card.Header>
          <Card.Title class="text-sm">Executions</Card.Title>
        </Card.Header>
        <Card.Content class="flex flex-col gap-1">
          {#each executions as execution (execution.id)}
            <div class="flex items-center justify-between text-xs">
              <span>{execution.action}</span>
              <Badge variant="outline">{execution.status}</Badge>
            </div>
          {:else}
            <p class="text-xs text-muted-foreground">None.</p>
          {/each}
        </Card.Content>
      </Card.Root>

      <Card.Root>
        <Card.Header>
          <Card.Title class="text-sm">Knowledge</Card.Title>
        </Card.Header>
        <Card.Content class="flex flex-col gap-1">
          {#each knowledge as hit (hit.id)}
            <div class="text-xs">
              <Badge variant="outline" class="mr-1">{hit.type}</Badge>{hit.title}
            </div>
          {:else}
            <p class="text-xs text-muted-foreground">None linked.</p>
          {/each}
        </Card.Content>
      </Card.Root>
    </div>

    <Card.Root>
      <Card.Header>
        <Card.Title class="text-sm">Recent events</Card.Title>
      </Card.Header>
      <Card.Content class="flex flex-col gap-1">
        {#each events as ev (ev.id)}
          <div class="flex items-center gap-2 text-xs">
            <span class="font-mono text-muted-foreground">{new Date(ev.ts).toLocaleString()}</span>
            <span>{ev.type}</span>
          </div>
        {:else}
          <p class="text-xs text-muted-foreground">No events yet.</p>
        {/each}
      </Card.Content>
    </Card.Root>
  {/if}
</div>
