<script lang="ts">
  import { activityLog, type ActivityEntry } from '$lib/stores/activity'
  import Spinner from './Spinner.svelte'
  import CircleDotIcon from '@lucide/svelte/icons/circle-dot'
  import CircleXIcon from '@lucide/svelte/icons/circle-x'
  import MilestoneIcon from '@lucide/svelte/icons/milestone'
  import ListTodoIcon from '@lucide/svelte/icons/list-todo'
  import SparklesIcon from '@lucide/svelte/icons/sparkles'
  import HelpCircleIcon from '@lucide/svelte/icons/help-circle'
  import FlagIcon from '@lucide/svelte/icons/flag'
  import ShieldIcon from '@lucide/svelte/icons/shield'
  import ChevronDownIcon from '@lucide/svelte/icons/chevron-down'
  import ChevronRightIcon from '@lucide/svelte/icons/chevron-right'

  let expanded = $state(new Set<string>())

  function toggle(id: string) {
    if (expanded.has(id)) expanded.delete(id)
    else expanded.add(id)
    expanded = new Set(expanded)
  }

  function typeIcon(type: ActivityEntry['type']) {
    switch (type) {
      case 'goal': return MilestoneIcon
      case 'plan': return ListTodoIcon
      case 'step_running': case 'step_done': case 'step_failed':
      case 'tool_running': case 'tool_done': case 'tool_error':
        return null // use status icon instead
      case 'knowledge': return SparklesIcon
      case 'complete': return FlagIcon
      case 'question': return HelpCircleIcon
      case 'approval': return ShieldIcon
      default: return null
    }
  }

  function statusColor(status: ActivityEntry['status']) {
    if (status === 'failed') return 'text-destructive'
    return 'text-primary'
  }

  // Tool results often arrive as a JSON string — pretty-print it when it
  // parses, otherwise fall back to the raw text rather than hiding it.
  function prettyPrint(raw: string): string {
    try {
      return JSON.stringify(JSON.parse(raw), null, 2)
    } catch {
      return raw
    }
  }

  function formatTime(ts: number): string | null {
    if (!ts) return null
    return new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })
  }
</script>

<div class="flex h-full flex-col">
  <div class="flex-1 overflow-y-auto">
    {#if $activityLog.length === 0}
      <div class="flex flex-col items-center gap-3 px-3 py-8 text-center">
        <svg viewBox="0 0 64 110" class="h-20 w-auto text-muted-foreground/40" fill="none">
          <line x1="32" y1="8" x2="32" y2="102" stroke="currentColor" stroke-width="1" stroke-dasharray="2.5 4" opacity="0.35" />
          <circle cx="32" cy="22" r="4" fill="currentColor">
            <animate attributeName="opacity" values="0.25;0.9;0.25" dur="2.4s" repeatCount="indefinite" />
          </circle>
          <circle cx="32" cy="55" r="4" fill="currentColor">
            <animate attributeName="opacity" values="0.25;0.9;0.25" dur="2.4s" begin="0.6s" repeatCount="indefinite" />
          </circle>
          <circle cx="32" cy="55" r="4" fill="none" stroke="currentColor" stroke-width="1.5">
            <animate attributeName="r" values="4;11;4" dur="2.4s" begin="0.6s" repeatCount="indefinite" />
            <animate attributeName="opacity" values="0.6;0;0.6" dur="2.4s" begin="0.6s" repeatCount="indefinite" />
          </circle>
          <circle cx="32" cy="88" r="4" fill="currentColor">
            <animate attributeName="opacity" values="0.25;0.9;0.25" dur="2.4s" begin="1.2s" repeatCount="indefinite" />
          </circle>
        </svg>
        <p class="max-w-[12rem] text-xs leading-relaxed text-muted-foreground">Waiting for activity…</p>
      </div>
    {:else}
      <div class="flex flex-col py-1">
        {#each $activityLog as entry, i (entry.id)}
          {@const isLast = i === $activityLog.length - 1}
          {@const icon = typeIcon(entry.type)}
          {@const isOpen = expanded.has(entry.id)}
          {@const time = formatTime(entry.timestamp)}
          <div class="relative">
            <!-- connector line -->
            {#if !isLast}
              <div class="absolute left-[17px] top-6 bottom-0 w-px bg-border"></div>
            {/if}
            <button
              type="button"
              class="flex w-full items-start gap-2 {entry.indent ? 'pl-7' : 'px-3'} py-1.5 text-left text-xs hover:bg-muted/30 cursor-pointer"
              onclick={() => toggle(entry.id)}
            >
              <!-- status icon -->
              <span class="relative mt-0.5 flex size-3.5 shrink-0 items-center justify-center rounded-full {statusColor(entry.status)}">
                {#if entry.status === 'running'}
                  <Spinner class="size-3.5" />
                {:else if entry.status === 'failed'}
                  <CircleXIcon class="size-3.5" />
                {:else if icon}
                  <svelte:component this={icon} class="size-3" />
                {:else}
                  <CircleDotIcon class="size-3" />
                {/if}
              </span>
              <!-- description -->
              <span class="min-w-0 flex-1 leading-snug {entry.status === 'done' ? 'text-muted-foreground' : ''}">
                {entry.description}
              </span>
              <span class="mt-0.5 shrink-0 text-muted-foreground">
                {#if isOpen}
                  <ChevronDownIcon class="size-3" />
                {:else}
                  <ChevronRightIcon class="size-3" />
                {/if}
              </span>
            </button>
            <!-- detail -->
            {#if isOpen}
              <div class="flex flex-col gap-1.5 pl-8 pr-3 pb-2">
                <div class="flex items-center gap-2 text-[10px] text-muted-foreground">
                  <span class="capitalize">{entry.status}</span>
                  {#if time}<span aria-hidden="true">·</span><span>{time}</span>{/if}
                  {#if entry.toolName}<span aria-hidden="true">·</span><code class="font-mono">{entry.toolName}</code>{/if}
                </div>
                {#if entry.args}
                  <div>
                    <p class="mb-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground/70">Called with</p>
                    <pre class="overflow-x-auto whitespace-pre-wrap break-words rounded bg-muted/50 p-2 font-mono text-[10px] leading-relaxed text-muted-foreground">{prettyPrint(entry.args)}</pre>
                  </div>
                {/if}
                {#if entry.detail}
                  <div>
                    {#if entry.args}<p class="mb-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground/70">{entry.status === 'failed' ? 'Error' : 'Result'}</p>{/if}
                    <pre class="overflow-x-auto whitespace-pre-wrap break-words rounded bg-muted/50 p-2 font-mono text-[10px] leading-relaxed text-muted-foreground">{prettyPrint(entry.detail)}</pre>
                  </div>
                {/if}
                {#if !entry.args && !entry.detail}
                  <p class="text-[10px] text-muted-foreground/70">No further detail for this step.</p>
                {/if}
              </div>
            {/if}
          </div>
        {/each}
      </div>
    {/if}
  </div>
</div>
