<script setup lang="ts">
/**
 * TaskDetailView – URL-basierte Task-Detailansicht (V2)
 *
 * Galaxy-theme konsistent mit TaskBoardView, aber als eigene Route.
 * Bietet:
 * 1. URL-basierte Task-Details (/tasks/:id)
 * 2. Verbesserte Kommentare/Aktivität (mit Typ + Timestamp)
 * 3. Subtasks direkt anlegen/bearbeiten
 */
import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
import { useQueryClient } from '@tanstack/vue-query'
import { RouterLink, useRoute, useRouter } from 'vue-router'
import {
  AlertCircle, ArrowLeft, Bot, CalendarDays, CheckCircle, Clock3,
  CornerDownRight, Hourglass, Link2, ListChecks, MessageSquare,
  Plus, Save, ShieldBan, Trash2, X,
} from '@lucide/vue'
import { apiFetch } from '../services/api'
import { useOpenClawOverviewQuery } from '../api/openclawRuntime'
import { queryKeys } from '../api/queryClient'
import {
  useTaskDetail,
  type DashboardTaskDto,
} from '../api/tasks'
import { reconcileTaskBoardCard } from '../api/taskBoard'
import { useAuthStore } from '../stores/auth'
import { reportOperationEnvelope } from '../services/operationResults'
import AsyncStatePanel from '../components/mission-control/AsyncStatePanel.vue'
import {
  buildTaskAgentOptions,
  taskAgentLabel,
} from '../utils/taskAgentOptions'

/* ── Types ──────────────────────────────────── */
type TaskDto = DashboardTaskDto

/* ── State ───────────────────────────────────── */
const route = useRoute()
const router = useRouter()
const queryClient = useQueryClient()
const authStore = useAuthStore()
const overviewQuery = useOpenClawOverviewQuery()
const taskId = computed(() => route.params.id as string)
const taskDetail = useTaskDetail(taskId)
const task = taskDetail.task
const children = taskDetail.children
const activity = taskDetail.activity
const relatedRuns = taskDetail.relatedRuns
const detailsLoading = taskDetail.detailsLoading
const loading = computed(() => taskDetail.taskQuery.isPending.value)
const localError = ref('')
const error = computed(() => {
  if (localError.value) return localError.value
  const queryError = taskDetail.taskQuery.error.value
  return queryError instanceof Error ? queryError.message : ''
})
const saving = ref(false)
const saveSuccess = ref(false)
const hydratedTaskId = ref<string | null>(null)

/* ── Edit Form ──────────────────────────────── */
const form = reactive({
  title: '',
  detail: '',
  state: 'Backlog',
  priority: 'Medium',
  assignedTo: '',
  dueDate: '',
})

/* ── Subtask creation ───────────────────────── */
const showNewSubtask = ref(false)
const subtaskTitle = ref('')
const subtaskDetail = ref('')
const subtaskPriority = ref('Medium')
const subtaskAssign = ref('')
const creatingSubtask = ref(false)
const subtaskError = ref('')
const taskAgentOptions = computed(() => buildTaskAgentOptions(
  overviewQuery.data.value?.agents.items ?? [],
  [
    form.assignedTo,
    subtaskAssign.value,
    task.value?.assignedTo,
    task.value?.expectedFrom,
    ...children.value.flatMap(child => [child.assignedTo, child.expectedFrom]),
  ],
))

/* ── Activity / Comments ────────────────────── */
const newComment = ref('')
const postingComment = ref(false)

/* ── Delete state ───────────────────────────── */
const deletingTask = ref('') // id of subtask being deleted
const canChangeState = computed(() => authStore.isIris || authStore.isBao)

/* ── Helpers ────────────────────────────────── */
function statusLabel(state: string): string {
  const map: Record<string, string> = {
    'Backlog': 'Offen',
    'In progress': 'In Bearbeitung',
    'Review': 'Review',
    'Blocked': 'Blockiert',
    'Done': 'Erledigt',
  }
  return map[state] || state
}

function statusClass(state: string): string {
  const s = state.toLowerCase()
  if (s === 'done') return 'is-done'
  if (s === 'blocked') return 'is-blocked'
  if (s === 'review') return 'is-review'
  if (s === 'in progress') return 'is-progress'
  return 'is-backlog'
}

function runStatusClass(status: string): string {
  const normalized = status.toLowerCase()
  if (normalized === 'completed' || normalized === 'stopped') return 'is-done'
  if (normalized === 'failed' || normalized === 'blocked') return 'is-blocked'
  if (normalized === 'running' || normalized === 'dispatching' || normalized === 'stopping') return 'is-progress'
  return 'is-backlog'
}

function priorityColor(p: string): string {
  const lower = p.toLowerCase()
  if (lower === 'high') return 'var(--st-block)'
  if (lower === 'low') return 'var(--a-cyan)'
  return 'var(--st-queue)'
}

function priorityLabel(p: string): string {
  const lower = p.toLowerCase()
  if (lower === 'high') return 'High'
  if (lower === 'low') return 'Low'
  return 'Med'
}

function formatDate(date?: string | null, withTime = false): string {
  if (!date) return '—'
  return new Date(date).toLocaleString('de-DE', withTime
    ? { dateStyle: 'medium', timeStyle: 'short' }
    : { dateStyle: 'medium' })
}

function toDateInput(date?: string | null): string {
  if (!date) return ''
  return new Date(date).toISOString().slice(0, 10)
}

function relativeTime(date?: string | null): string {
  if (!date) return 'keine Updates'
  const diffMs = Date.now() - new Date(date).getTime()
  const mins = Math.max(0, Math.round(diffMs / 60000))
  if (mins < 1) return 'gerade eben'
  if (mins < 60) return `vor ${mins} min`
  const hours = Math.round(mins / 60)
  if (hours < 24) return `vor ${hours} h`
  const days = Math.round(hours / 24)
  return `vor ${days} d`
}

function childStatusSummary(taskId: string): string {
  const childItems = children.value.filter(child => child.parentTaskId === taskId)
  if (!childItems.length) return ''

  const counts = {
    inProgress: childItems.filter(child => child.state === 'In progress').length,
    review: childItems.filter(child => child.state === 'Review').length,
    blocked: childItems.filter(child => child.state === 'Blocked').length,
    done: childItems.filter(child => child.state === 'Done').length,
  }

  const parts = [] as string[]
  if (counts.inProgress) parts.push(`${counts.inProgress} in Arbeit`)
  if (counts.review) parts.push(`${counts.review} im Review`)
  if (counts.blocked) parts.push(`${counts.blocked} blockiert`)
  if (counts.done) parts.push(`${counts.done} erledigt`)
  return parts.length ? `Child-Tasks: ${parts.join(' · ')}` : `Child-Tasks: ${childItems.length}`
}

function progressHint(taskLike: Pick<TaskDto, 'id' | 'lastActivityMessage' | 'expectedFrom'>): string {
  return taskLike.lastActivityMessage?.trim()
    || childStatusSummary(taskLike.id)
    || (taskLike.expectedFrom ? `Wartet auf ${agentLabel(taskLike.expectedFrom)}` : 'Noch kein relevanter Progress-Status')
}

function agentLabel(value: string | null | undefined): string {
  return taskAgentLabel(value, taskAgentOptions.value)
}

function delegationSummary(taskLike: TaskDto): string | null {
  if (taskLike.parentTaskId) return 'Sichtbare Child-Delegation'
  if (children.value.length) return `${children.value.length} sichtbare Child-Tasks`
  if (taskLike.isAgentTask) return 'Delegation im Board sichtbar'
  return null
}

/* ── API calls ───────────────────────────────── */
function hydrateForm(data: TaskDto) {
  form.title = data.title
  form.detail = data.detail ?? ''
  form.state = data.state
  form.priority = data.priority
  form.assignedTo = data.assignedTo ?? ''
  form.dueDate = toDateInput(data.dueDate)
  hydratedTaskId.value = data.id
}

async function consumeMutationResponse(
  response: Response,
  title: string,
  fallback: string,
): Promise<unknown> {
  const payload = await response.json().catch(() => null)
  reportOperationEnvelope(payload, title)
  if (!response.ok) {
    const failure = payload as { detail?: string; message?: string; title?: string } | null
    throw new Error(failure?.detail || failure?.message || failure?.title || fallback)
  }
  return payload
}

async function loadTask() {
  localError.value = ''
  const result = await taskDetail.taskQuery.refetch()
  if (result.error) {
    localError.value = result.error instanceof Error
      ? result.error.message
      : 'Aufgabe konnte nicht geladen werden'
    return
  }
  if (result.data) hydrateForm(result.data)
  await loadDetails()
}

async function loadDetails() {
  await Promise.all([
    taskDetail.childrenQuery.refetch(),
    taskDetail.activityQuery.refetch(),
    taskDetail.runsQuery.refetch(),
  ])
}

async function saveTask() {
  if (!task.value || !form.title.trim()) return
  saving.value = true
  saveSuccess.value = false
  localError.value = ''
  try {
    const res = await apiFetch(`/api/dashboard/tasks/${taskId.value}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        title: form.title.trim(),
        detail: form.detail.trim() || null,
        priority: form.priority,
        assignedTo: form.assignedTo || null,
        dueDate: form.dueDate || null,
      }),
    })
    await consumeMutationResponse(res, 'Task aktualisiert', `HTTP ${res.status}`)
    // Also update state if changed
    if (form.state !== task.value.state) {
      if (!canChangeState.value) {
        form.state = task.value.state
      } else {
        const stateRes = await apiFetch(`/api/dashboard/tasks/${taskId.value}/status`, {
          method: 'PATCH',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ status: form.state }),
        })
        await consumeMutationResponse(stateRes, 'Task-Status aktualisiert', 'Status-Update fehlgeschlagen')
      }
    }
    saveSuccess.value = true
    await loadTask()
    await reconcileTaskBoardCard(taskId.value)
  } catch (e) {
    localError.value = e instanceof Error ? e.message : 'Speichern fehlgeschlagen'
  } finally {
    saving.value = false
  }
}

async function createSubtask() {
  if (!subtaskTitle.value.trim()) return
  creatingSubtask.value = true
  subtaskError.value = ''
  try {
    const res = await apiFetch('/api/dashboard/tasks', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        title: subtaskTitle.value.trim(),
        detail: subtaskDetail.value.trim() || null,
        priority: subtaskPriority.value,
        assignedTo: subtaskAssign.value || null,
        parentTaskId: taskId.value,
        source: 'bao',
      }),
    })
    await consumeMutationResponse(res, 'Subtask erstellt', `HTTP ${res.status}`)
    showNewSubtask.value = false
    subtaskTitle.value = ''
    subtaskDetail.value = ''
    subtaskPriority.value = 'Medium'
    subtaskAssign.value = ''
    await queryClient.invalidateQueries({ queryKey: queryKeys.taskChildren(taskId.value) })
    await queryClient.invalidateQueries({ queryKey: queryKeys.task(taskId.value) })
    await reconcileTaskBoardCard(taskId.value)
  } catch (e) {
    subtaskError.value = e instanceof Error ? e.message : 'Fehler beim Anlegen'
  } finally {
    creatingSubtask.value = false
  }
}

async function updateSubtaskState(subtaskId: string, newState: string) {
  if (!canChangeState.value) return
  try {
    const response = await apiFetch(`/api/dashboard/tasks/${subtaskId}/status`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ status: newState }),
    })
    await consumeMutationResponse(response, 'Subtask-Status aktualisiert', 'Status-Update fehlgeschlagen')
    await queryClient.invalidateQueries({ queryKey: queryKeys.taskChildren(taskId.value) })
    await reconcileTaskBoardCard(subtaskId)
    await reconcileTaskBoardCard(taskId.value)
  } catch {
    // silent
  }
}

async function deleteSubtask(subtaskId: string) {
  deletingTask.value = subtaskId
  try {
    const response = await apiFetch(`/api/dashboard/tasks/${subtaskId}`, { method: 'DELETE' })
    await consumeMutationResponse(response, 'Subtask gelöscht', 'Subtask konnte nicht gelöscht werden')
    await queryClient.invalidateQueries({ queryKey: queryKeys.taskChildren(taskId.value) })
    await reconcileTaskBoardCard(taskId.value)
  } catch {
    // silent
  } finally {
    deletingTask.value = ''
  }
}

async function postComment() {
  if (!newComment.value.trim()) return
  postingComment.value = true
  try {
    // Use activity endpoint to log a comment
    const response = await apiFetch(`/api/dashboard/tasks/${taskId.value}/activity`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        type: 'comment',
        message: newComment.value.trim(),
      }),
    })
    await consumeMutationResponse(response, 'Kommentar hinzugefügt', 'Kommentar konnte nicht gespeichert werden')
    newComment.value = ''
    await queryClient.invalidateQueries({ queryKey: queryKeys.taskActivity(taskId.value) })
  } catch {
    // silent
  } finally {
    postingComment.value = false
  }
}

/* ── Lifecycle ───────────────────────────────── */
watch(taskId, () => {
  hydratedTaskId.value = null
  localError.value = ''
})

watch(
  () => taskDetail.taskQuery.data.value,
  data => {
    if (data && hydratedTaskId.value !== data.id) hydrateForm(data)
  },
  { immediate: true },
)

function goBack() {
  router.push('/tasks')
}

onMounted(() => {
  window.addEventListener('keydown', handleKeydown)
})

onBeforeUnmount(() => {
  window.removeEventListener('keydown', handleKeydown)
})

function handleKeydown(e: KeyboardEvent) {
  if (e.key === 'Escape') goBack()
}
</script>

<template>
  <div class="detail-wrap nexus-page nexus-page--reading">
    <!-- Back -->
    <button type="button" class="back-btn" @click="goBack">
      <ArrowLeft :size="16" />
      Zurück zum Board
    </button>

    <AsyncStatePanel
      v-if="loading && !task"
      state="loading"
      title="Aufgabe wird geladen"
    />

    <AsyncStatePanel
      v-else-if="error && !task"
      state="error"
      title="Aufgabe konnte nicht geladen werden"
      :problem="taskDetail.taskQuery.error.value"
      :message="error"
      @action="loadTask"
    />

    <!-- Task Detail -->
    <template v-else-if="task">
      <h1 class="nexus-visually-hidden">{{ task.title }}</h1>
      <div class="detail-header">
        <div class="detail-meta-top">
          <span class="state-badge" :class="statusClass(task.state)">{{ statusLabel(task.state) }}</span>
          <span class="meta-chip" v-if="task.source">Quelle: {{ task.source }}</span>
          <span class="meta-chip">{{ task.priority }} Priorität</span>
          <span v-if="task.isAgentTask" class="meta-chip"><Bot :size="12" aria-hidden="true" /> Agent-Task</span>
          <span v-if="task.expectedFrom" class="meta-chip"><Hourglass :size="11" aria-hidden="true" /> Erwartet: {{ agentLabel(task.expectedFrom) }}</span>
          <span v-if="task.parentTaskId" class="meta-chip"><CornerDownRight :size="11" aria-hidden="true" /> Sichtbare Child-Task</span>
          <span v-if="delegationSummary(task)" class="meta-chip">{{ delegationSummary(task) }}</span>
        </div>
      </div>

      <div v-if="!canChangeState" class="readonly-banner">
        <ShieldBan :size="14" />
        Inhalte sind editierbar, Statuswechsel bleiben Bao/Iris vorbehalten.
      </div>

      <div class="detail-body">
        <!-- Main Column -->
        <div class="detail-main">
          <input v-model="form.title" class="title-input" maxlength="240" aria-label="Titel der Aufgabe" placeholder="Titel der Aufgabe" />

          <div class="meta-row">
            <span>
              <Clock3 :size="13" />
              Erstellt {{ formatDate(task.createdAt) }}
            </span>
            <span>
              <CalendarDays :size="13" />
              Aktualisiert {{ formatDate(task.updatedAt, true) }}
            </span>
            <span v-if="task.isAgentTask">
              <MessageSquare :size="13" />
              Letzter Status {{ relativeTime(task.lastActivityAt ?? task.updatedAt) }}
            </span>
          </div>

          <div v-if="task.isAgentTask || childStatusSummary(task.id) || delegationSummary(task)" class="progress-banner">
            <strong>Letzter Fortschritt:</strong> {{ progressHint(task) }}
            <span v-if="delegationSummary(task)" class="delegation-inline">· {{ delegationSummary(task) }}</span>
          </div>

          <!-- Description -->
          <section class="section-card">
            <div class="section-head">Beschreibung</div>
            <textarea
              v-model="form.detail"
              class="detail-textarea"
              rows="8"
              placeholder="Kontext, Akzeptanzkriterien, Notizen…"
            ></textarea>
          </section>

          <!-- Subtasks -->
          <section class="section-card">
            <div class="section-head">
              <ListChecks :size="14" />
              Unteraufgaben
              <button
                type="button"
                class="btn-icon-sm"
                aria-label="Unteraufgabe anlegen"
                @click="showNewSubtask = !showNewSubtask"
                title="Unteraufgabe anlegen"
              >
                <Plus :size="14" />
              </button>
            </div>

            <div v-if="showNewSubtask" class="new-subtask-form">
              <input v-model="subtaskTitle" class="galaxy-input" placeholder="Unteraufgabe Titel" maxlength="240" />
              <textarea v-model="subtaskDetail" class="galaxy-input mini-textarea" placeholder="Details (optional)" rows="2"></textarea>
              <div class="subtask-form-row">
                <select v-model="subtaskPriority" class="galaxy-input galaxy-select narrow" aria-label="Priorität der Unteraufgabe">
                  <option value="High">High</option>
                  <option value="Medium">Medium</option>
                  <option value="Low">Low</option>
                </select>
                <select v-model="subtaskAssign" class="galaxy-input galaxy-select narrow" aria-label="Zuständigkeit der Unteraufgabe">
                  <option v-for="option in taskAgentOptions" :key="option.id || 'unassigned'" :value="option.id">
                    {{ option.label }}
                  </option>
                </select>
                <button type="button" class="btn-primary btn-sm" @click="createSubtask" :disabled="creatingSubtask">
                  {{ creatingSubtask ? 'Erstelle…' : 'Anlegen' }}
                </button>
              </div>
              <p v-if="subtaskError" class="msg error">{{ subtaskError }}</p>
            </div>

            <div v-if="detailsLoading" class="loading-mini">
              <div class="spinner-sm"></div>
              Lade Unteraufgaben…
            </div>
            <div v-else-if="children.length === 0" class="empty-section">
              <p>Keine Unteraufgaben vorhanden.</p>
              <p class="hint">Klicke auf <Plus :size="12" /> um eine anzulegen.</p>
            </div>
            <div v-else class="subtask-list">
              <div v-for="child in children" :key="child.id" class="subtask-row">
                <div class="subtask-info">
                  <RouterLink
                    class="subtask-title entity-link"
                    :to="{ name: 'TaskDetail', params: { id: child.id } }"
                  >
                    {{ child.title }}
                  </RouterLink>
                  <p v-if="child.detail" class="subtask-detail">{{ child.detail }}</p>
                </div>
                <div class="subtask-actions">
                  <select
                    :value="child.state"
                    class="state-select-mini"
                    :disabled="!canChangeState"
                    @change="updateSubtaskState(child.id, ($event.target as HTMLSelectElement).value)"
                  >
                    <option value="Backlog">Offen</option>
                    <option value="In progress">In Arbeit</option>
                    <option value="Review">Review</option>
                    <option value="Blocked">Blockiert</option>
                    <option value="Done">Erledigt</option>
                  </select>
                  <button
                    type="button"
                    class="btn-icon-sm danger"
                    @click="deleteSubtask(child.id)"
                    :disabled="deletingTask === child.id"
                    :aria-label="`Unteraufgabe ${child.title} löschen`"
                    title="Löschen"
                  >
                    <Trash2 :size="13" />
                  </button>
                </div>
              </div>
            </div>
          </section>

          <!-- Activity / Comments -->
          <section class="section-card">
            <div class="section-head">
              <MessageSquare :size="14" />
              Aktivität &amp; Kommentare
            </div>

            <div class="comment-input-row">
              <input
                v-model="newComment"
                class="galaxy-input"
                placeholder="Kommentar oder Notiz hinzufügen…"
                @keydown.enter.prevent="postComment"
              />
              <button type="button" class="btn-primary btn-sm" @click="postComment" :disabled="postingComment || !newComment.trim()">
                Senden
              </button>
            </div>

            <div v-if="detailsLoading" class="loading-mini">
              <div class="spinner-sm"></div>
              Lade Aktivität…
            </div>
            <div v-else-if="activity.length === 0" class="empty-section">
              Noch keine Aktivität vorhanden.
            </div>
            <div v-else class="activity-list">
              <div v-for="(entry, idx) in activity" :key="entry.id ?? idx" class="activity-item">
                <div class="activity-icon">
                  <MessageSquare v-if="entry.type === 'comment'" :size="12" />
                  <Link2 v-else :size="12" />
                </div>
                <div class="activity-body">
                  <div class="activity-msg">{{ entry.message ?? '—' }}</div>
                  <div class="activity-time">{{ formatDate(entry.createdAt ?? null, true) }}</div>
                </div>
              </div>
            </div>
          </section>

          <section class="section-card">
            <div class="section-head">
              <Bot :size="14" />
              Zugehörige Runs
            </div>
            <div v-if="detailsLoading" class="loading-mini">
              <div class="spinner-sm"></div>
              Lade Run-Verlauf…
            </div>
            <div v-else-if="relatedRuns.length === 0" class="empty-section">
              Für diese Aufgabe wurde noch kein OpenClaw-Run erfasst.
            </div>
            <div v-else class="related-run-list">
              <RouterLink
                v-for="run in relatedRuns"
                :key="run.id"
                class="related-run"
                :to="{ name: 'RunDetail', params: { id: run.id } }"
              >
                <span>
                  <strong>{{ run.title }}</strong>
                  <small>{{ run.agentId }} · {{ formatDate(run.updatedAt, true) }}</small>
                </span>
                <span class="state-badge" :class="runStatusClass(run.status)">{{ run.status }}</span>
              </RouterLink>
            </div>
          </section>
        </div>

        <!-- Sidebar -->
        <div class="detail-sidebar">
          <section class="sidebar-card">
            <div class="sidebar-head">Eigenschaften</div>
            <label class="sidebar-field">
              <span>Status</span>
              <select v-model="form.state" class="galaxy-input galaxy-select" :disabled="!canChangeState">
                <option value="Backlog">Offen</option>
                <option value="In progress">In Bearbeitung</option>
                <option value="Review">Review</option>
                <option value="Blocked">Blockiert</option>
                <option value="Done">Erledigt</option>
              </select>
            </label>
            <label class="sidebar-field">
              <span>Priorität</span>
              <select v-model="form.priority" class="galaxy-input galaxy-select">
                <option value="High">High</option>
                <option value="Medium">Medium</option>
                <option value="Low">Low</option>
              </select>
            </label>
            <label class="sidebar-field">
              <span>Zuständig</span>
              <select v-model="form.assignedTo" class="galaxy-input galaxy-select">
                <option v-for="option in taskAgentOptions" :key="option.id || 'unassigned'" :value="option.id">
                  {{ option.label }}
                </option>
              </select>
            </label>
            <label class="sidebar-field">
              <span>Fällig am</span>
              <input v-model="form.dueDate" type="date" class="galaxy-input" />
            </label>
          </section>

          <section class="sidebar-card subtle">
            <div class="sidebar-head">Informationen</div>
            <dl class="info-list">
              <div><dt>ID</dt><dd>#{{ task.id.slice(0, 8) }}</dd></div>
              <div><dt>Quelle</dt><dd>{{ task.source || '—' }}</dd></div>
              <div v-if="task.projectId">
                <dt>Projekt</dt>
                <dd>
                  <RouterLink class="entity-link" :to="{ name: 'ProjectDetail', params: { id: task.projectId } }">
                    Projekt öffnen
                  </RouterLink>
                </dd>
              </div>
              <div v-if="task.assignedTo || task.expectedFrom">
                <dt>Agent</dt>
                <dd>
                  <RouterLink
                    class="entity-link"
                    :to="{ name: 'AgentDetail', params: { id: task.assignedTo ?? task.expectedFrom ?? '' } }"
                  >
                    {{ agentLabel(task.assignedTo || task.expectedFrom) }}
                  </RouterLink>
                </dd>
              </div>
              <div v-if="task.parentTaskId">
                <dt>Parent</dt>
                <dd>
                  <RouterLink class="entity-link" :to="{ name: 'TaskDetail', params: { id: task.parentTaskId } }">
                    Parent-Task öffnen
                  </RouterLink>
                </dd>
              </div>
              <div v-if="delegationSummary(task)"><dt>Delegation</dt><dd>{{ delegationSummary(task) }}</dd></div>
              <div><dt>Erstellt</dt><dd>{{ formatDate(task.createdAt) }}</dd></div>
              <div><dt>Geändert</dt><dd>{{ formatDate(task.updatedAt, true) }}</dd></div>
              <div v-if="task.isAgentTask"><dt>Letzter Status</dt><dd>{{ relativeTime(task.lastActivityAt ?? task.updatedAt) }}</dd></div>
              <div v-if="task.expectedFrom"><dt>Erwartet von</dt><dd>{{ agentLabel(task.expectedFrom) }}</dd></div>
              <div v-if="task.parentTaskId"><dt>Task-Typ</dt><dd>Sichtbare Child-Task</dd></div>
            </dl>
          </section>

          <p v-if="error" class="msg error">{{ error }}</p>
          <p v-if="saveSuccess" class="msg success">
            <CheckCircle :size="14" /> Gespeichert.
          </p>

          <div class="detail-actions">
            <button type="button" class="btn-ghost" @click="goBack">Schließen</button>
            <button type="button" class="btn-primary" :disabled="saving || !form.title.trim()" @click="saveTask">
              <Save :size="14" />
              {{ saving ? 'Speichert…' : 'Speichern' }}
            </button>
          </div>
        </div>
      </div>
    </template>
  </div>
</template>

<style scoped>
.detail-wrap {
  width: 100%;
  max-width: 1120px;
  margin: 0 auto;
  padding: 20px;
  animation: fadeIn 0.3s ease-out;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ── Back ───────────────────────────────────── */
.back-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border: 1px solid color-mix(in srgb, var(--a-mid) 12%, transparent);
  border-radius: 10px;
  background: transparent;
  color: var(--tx-2);
  font-size: 12px;
  font-family: 'Manrope', sans-serif;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
  margin-bottom: 20px;
}

.back-btn:hover {
  background: color-mix(in srgb, var(--a-mid) 8%, transparent);
  color: var(--tx);
}

/* ── Loading / Error ────────────────────────── */
.loading-state, .error-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 80px 20px;
  color: var(--tx-3);
}

.spinner {
  width: 24px;
  height: 24px;
  border: 2.5px solid color-mix(in srgb, var(--a-mid) 15%, transparent);
  border-top-color: var(--a-mid);
  border-radius: 50%;
  animation: spin 0.6s linear infinite;
}

.spinner-sm {
  width: 16px;
  height: 16px;
  border: 2px solid color-mix(in srgb, var(--a-mid) 15%, transparent);
  border-top-color: var(--a-mid);
  border-radius: 50%;
  animation: spin 0.6s linear infinite;
  flex-shrink: 0;
}

@keyframes spin { to { transform: rotate(360deg); } }

.error-state p {
  font-size: 14px;
  margin: 0;
  color: var(--st-block);
}

/* ── Detail Header ──────────────────────────── */
.detail-header {
  margin-bottom: 20px;
}

.detail-meta-top {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.state-badge {
  display: inline-block;
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.03em;
  border: 1px solid transparent;
}

.state-badge.is-backlog { color: var(--st-queue); background: color-mix(in srgb, var(--st-queue) 12%, transparent); border-color: color-mix(in srgb, var(--st-queue) 25%, transparent); }
.state-badge.is-progress { color: var(--st-work); background: color-mix(in srgb, var(--st-work) 12%, transparent); border-color: color-mix(in srgb, var(--st-work) 25%, transparent); }
.state-badge.is-review { color: var(--st-review); background: color-mix(in srgb, var(--st-review) 12%, transparent); border-color: color-mix(in srgb, var(--st-review) 25%, transparent); }
.state-badge.is-blocked { color: var(--st-block); background: color-mix(in srgb, var(--st-block) 12%, transparent); border-color: color-mix(in srgb, var(--st-block) 25%, transparent); }
.state-badge.is-done { color: var(--st-work); background: color-mix(in srgb, var(--st-work) 12%, transparent); border-color: color-mix(in srgb, var(--st-work) 25%, transparent); }

.meta-chip {
  font-size: 10px;
  color: var(--tx-3);
  background: color-mix(in srgb, var(--space-1) 35%, transparent);
  padding: 3px 10px;
  border-radius: 6px;
  border: 1px solid color-mix(in srgb, var(--a-mid) 8%, transparent);
}

.readonly-banner {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 16px;
  padding: 10px 12px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--a-purple) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--a-purple) 18%, transparent);
  color: var(--a-purple);
  font-size: 12px;
}

/* ── Detail Body Grid ────────────────────────── */
.detail-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 24px;
  align-items: start;
}

.detail-main {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.title-input {
  width: 100%;
  background: transparent;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 4px 0;
  color: var(--tx);
  font-family: 'Space Grotesk', sans-serif;
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.03em;
  outline: none;
  transition: border-color 0.2s;
}

.title-input:focus {
  border-bottom-color: color-mix(in srgb, var(--a-mid) 30%, transparent);
}

.meta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  font-size: 12px;
  color: var(--tx-3);
}

.meta-row span {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.progress-banner {
  padding: 12px 14px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--a-mid) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--a-mid) 14%, transparent);
  color: var(--tx-2);
  font-size: 12px;
}

/* ── Sections ──────────────────────────── */
.section-card {
  border: 1px solid color-mix(in srgb, var(--a-mid) 10%, transparent);
  border-radius: 16px;
  padding: 18px;
  background: color-mix(in srgb, var(--space-1) 25%, transparent);
}

.section-head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 14px;
  color: var(--tx-2);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.section-head button {
  margin-left: auto;
}

.detail-textarea {
  width: 100%;
  min-height: 160px;
  padding: 14px;
  border: 1px solid color-mix(in srgb, var(--a-mid) 10%, transparent);
  border-radius: 12px;
  background: color-mix(in srgb, var(--space-1) 45%, transparent);
  color: var(--tx);
  font-size: 14px;
  line-height: 1.6;
  font-family: 'Manrope', sans-serif;
  outline: none;
  resize: vertical;
  box-sizing: border-box;
  transition: border-color 0.2s;
}

.detail-textarea:focus {
  border-color: color-mix(in srgb, var(--a-mid) 30%, transparent);
}

/* ── Subtasks ──────────────────────────── */
.new-subtask-form {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px;
  margin-bottom: 14px;
  border: 1px solid color-mix(in srgb, var(--a-mid) 15%, transparent);
  border-radius: 12px;
  background: color-mix(in srgb, var(--a-mid) 4%, transparent);
}

.subtask-form-row {
  display: flex;
  gap: 8px;
  align-items: center;
}

.subtask-form-row .narrow {
  flex: 1;
  min-width: 0;
}

.mini-textarea {
  resize: vertical;
}

.subtask-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.subtask-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--space-1) 35%, transparent);
  border: 1px solid color-mix(in srgb, var(--a-mid) 6%, transparent);
  transition: background 0.15s;
}

.subtask-row:hover {
  background: color-mix(in srgb, var(--space-1) 50%, transparent);
  border-color: color-mix(in srgb, var(--a-mid) 10%, transparent);
}

.subtask-info {
  flex: 1;
  min-width: 0;
}

.subtask-title {
  font-size: 13px;
  font-weight: 600;
  color: var(--tx);
}

.subtask-detail {
  margin: 4px 0 0;
  font-size: 11.5px;
  color: var(--tx-3);
  line-height: 1.4;
}

.subtask-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
}

.state-select-mini {
  padding: 4px 8px;
  border: 1px solid color-mix(in srgb, var(--a-mid) 12%, transparent);
  border-radius: 6px;
  background: color-mix(in srgb, var(--space-1) 50%, transparent);
  color: var(--tx-2);
  font-size: 10px;
  font-family: 'Manrope', sans-serif;
  cursor: pointer;
  outline: none;
}

.state-select-mini option {
  background: var(--space-3);
  color: var(--tx);
}

.state-select-mini:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.loading-mini {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 16px;
  color: var(--tx-3);
  font-size: 12px;
}

.empty-section {
  padding: 20px;
  text-align: center;
  color: var(--tx-3);
  font-size: 12px;
}

.empty-section p { margin: 0; }
.empty-section .hint {
  margin-top: 6px;
  font-size: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
}

/* ── Activity / Comments ─────────────────── */
.comment-input-row {
  display: flex;
  gap: 8px;
  margin-bottom: 14px;
}

.comment-input-row .galaxy-input {
  flex: 1;
}

.activity-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.activity-item {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  padding: 10px 12px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--space-1) 20%, transparent);
  border: 1px solid color-mix(in srgb, var(--a-mid) 4%, transparent);
}

.activity-icon {
  width: 26px;
  height: 26px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  background: color-mix(in srgb, var(--a-mid) 8%, transparent);
  color: var(--a-mid);
  flex-shrink: 0;
}

.activity-body {
  flex: 1;
  min-width: 0;
}

.activity-msg {
  font-size: 12.5px;
  color: var(--tx-2);
  line-height: 1.4;
}

.activity-time {
  font-size: 10px;
  color: var(--tx-3);
  margin-top: 3px;
}

.related-run-list {
  display: grid;
  gap: 8px;
}

.related-run {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 12px;
  border: 1px solid color-mix(in srgb, var(--a-mid) 8%, transparent);
  border-radius: 10px;
  background: color-mix(in srgb, var(--space-1) 25%, transparent);
  color: var(--tx);
  text-decoration: none;
}

.related-run:hover {
  border-color: color-mix(in srgb, var(--a-mid) 24%, transparent);
  background: color-mix(in srgb, var(--a-mid) 6%, transparent);
}

.related-run > span:first-child {
  min-width: 0;
}

.related-run strong,
.related-run small {
  display: block;
}

.related-run strong {
  overflow: hidden;
  font-size: 12.5px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.related-run small {
  margin-top: 3px;
  color: var(--tx-3);
  font: 10.5px 'JetBrains Mono', monospace;
}

.entity-link {
  color: var(--a-cyan);
  text-decoration: none;
}

.entity-link:hover {
  color: var(--tx);
  text-decoration: underline;
}

.entity-link:focus-visible,
.related-run:focus-visible {
  outline: 2px solid var(--a-mid);
  outline-offset: 3px;
}

/* ── Sidebar ──────────────────────────── */
.detail-sidebar {
  display: flex;
  flex-direction: column;
  gap: 14px;
  position: sticky;
  top: 20px;
}

.sidebar-card {
  border: 1px solid color-mix(in srgb, var(--a-mid) 10%, transparent);
  border-radius: 16px;
  padding: 18px;
  background: color-mix(in srgb, var(--space-1) 35%, transparent);
}

.sidebar-card.subtle {
  background: color-mix(in srgb, var(--tx) 1%, transparent);
}

.sidebar-head {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--tx-2);
  margin-bottom: 14px;
}

.sidebar-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 12px;
}

.sidebar-field:last-child {
  margin-bottom: 0;
}

.sidebar-field span {
  font-size: 10px;
  font-weight: 600;
  color: var(--tx-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.info-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0;
}

.info-list div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}

.info-list dt {
  color: var(--tx-3);
  font-size: 11px;
}

.info-list dd {
  margin: 0;
  color: var(--tx-2);
  font-size: 11.5px;
  text-align: right;
}

.detail-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 4px;
}

/* ── Shared Components ───────────────────── */
.galaxy-input {
  width: 100%;
  padding: 10px 14px;
  border: 1px solid color-mix(in srgb, var(--a-mid) 12%, transparent);
  border-radius: 10px;
  background: color-mix(in srgb, var(--space-1) 55%, transparent);
  color: var(--tx);
  font-size: 13.5px;
  font-family: 'Manrope', sans-serif;
  outline: none;
  transition: border-color 0.2s;
  box-sizing: border-box;
}

.galaxy-input:focus {
  border-color: color-mix(in srgb, var(--a-mid) 50%, transparent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--a-mid) 12%, transparent);
}

.galaxy-select {
  cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236f6aa0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 36px;
}

.galaxy-select option {
  background: var(--space-3);
  color: var(--tx);
}

.galaxy-select:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-primary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 9px 16px;
  border: none;
  border-radius: 10px;
  background: linear-gradient(135deg, var(--a-blue), var(--a-mid), var(--a-purple));
  color: var(--tx);
  font-size: 12.5px;
  font-weight: 600;
  font-family: 'Manrope', sans-serif;
  cursor: pointer;
  transition: opacity 0.2s;
}

.btn-primary:hover:not(:disabled) { opacity: 0.9; }
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; }

.btn-sm {
  padding: 6px 12px;
  font-size: 11px;
  border-radius: 8px;
}

.btn-ghost {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border: 1px solid color-mix(in srgb, var(--a-mid) 12%, transparent);
  border-radius: 8px;
  background: transparent;
  color: var(--tx-2);
  font-size: 11px;
  font-family: 'Manrope', sans-serif;
  cursor: pointer;
  transition: background 0.15s;
}

.btn-ghost:hover { background: color-mix(in srgb, var(--a-mid) 8%, transparent); }

.btn-icon-sm {
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 7px;
  background: color-mix(in srgb, var(--a-mid) 6%, transparent);
  color: var(--tx-2);
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}

.btn-icon-sm:hover { background: color-mix(in srgb, var(--a-mid) 12%, transparent); color: var(--tx); }
.btn-icon-sm.danger:hover { background: color-mix(in srgb, var(--st-block) 12%, transparent); color: var(--st-block); }
.btn-icon-sm:disabled { opacity: 0.4; cursor: not-allowed; }

.msg {
  margin: 0;
  font-size: 11px;
  padding: 8px 12px;
  border-radius: 8px;
}

.msg.error { background: color-mix(in srgb, var(--st-block) 8%, transparent); border: 1px solid color-mix(in srgb, var(--st-block) 15%, transparent); color: var(--st-block); }
.msg.success { background: color-mix(in srgb, var(--st-work) 8%, transparent); border: 1px solid color-mix(in srgb, var(--st-work) 15%, transparent); color: var(--st-work); display: flex; align-items: center; gap: 6px; }

/* ── Responsive ──────────────────────────────── */
@media (max-width: 860px) {
  .detail-body {
    grid-template-columns: 1fr;
  }
  .detail-sidebar {
    position: static;
  }
  .title-input {
    font-size: 22px;
  }
}
</style>
