<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { api, ApiError, type TaskFull, type PipelineStep, type PendingAction, type DeployResult, type Attachment } from '../api'
import Badge from '../components/Badge.vue'
import Modal from '../components/Modal.vue'
import AttachmentUploader from '../components/AttachmentUploader.vue'
import AttachmentList from '../components/AttachmentList.vue'
import LiveConsole from '../components/LiveConsole.vue'

const props = defineProps<{ id: string }>()
const route = useRoute()
const router = useRouter()

const task = ref<TaskFull | null>(null)
const loading = ref(true)
const error = ref('')
const claudeLoginError = ref(false)
const selectedStep = ref<PipelineStep | null>(null)
const polling = ref(false)
const pipelineStarting = ref(false)
let pollTimer: ReturnType<typeof setInterval> | null = null

// Approve modal
const showApprove = ref(false)
const approveForm = ref({ title: '', description: '', type: 'decision', createFollowups: true })
const approveLoading = ref(false)
const followupResults = ref<{ id: string; title: string }[]>([])
const pendingActions = ref<PendingAction[]>([])
const resolvingAction = ref(false)

// Reject modal
const showReject = ref(false)
const rejectReason = ref('')

// Revise modal
const showRevise = ref(false)
const reviseComment = ref('')

const parsedSelectedOutput = computed<ParsedAgentOutput | null>(() => {
  if (!selectedStep.value) return null
  return parseAgentOutput(selectedStep.value.output_summary)
})

// Auto/Review mode (per-task, persisted in DB; falls back to localStorage per project)
const autoMode = ref(false)

function loadMode(t: typeof task.value) {
  if (!t) return
  if (t.execution_mode) {
    autoMode.value = t.execution_mode === 'auto_complete'
  } else if (t.status === 'review') {
    // Task is in review — always show Approve/Reject regardless of localStorage
    autoMode.value = false
  } else {
    autoMode.value = localStorage.getItem(`kin-mode-${t.project_id}`) === 'auto_complete'
  }
}

async function toggleMode() {
  if (!task.value) return
  autoMode.value = !autoMode.value
  localStorage.setItem(`kin-mode-${task.value.project_id}`, autoMode.value ? 'auto_complete' : 'review')
  try {
    const updated = await api.patchTask(props.id, { execution_mode: autoMode.value ? 'auto_complete' : 'review' })
    task.value = { ...task.value, ...updated }
  } catch (e: any) {
    error.value = e.message
  }
}

async function load() {
  try {
    const prev = task.value
    task.value = await api.taskFull(props.id)
    loadMode(task.value)
    // Auto-start polling if task is in_progress
    if (task.value.status === 'in_progress' && !polling.value) {
      startPolling()
    }
    // Stop polling when pipeline done
    if (prev?.status === 'in_progress' && task.value.status !== 'in_progress') {
      stopPolling()
    }
  } catch (e: any) {
    error.value = e.message
  } finally {
    loading.value = false
  }
}

function startPolling() {
  if (polling.value) return
  polling.value = true
  pollTimer = setInterval(load, 3000)
}

function stopPolling() {
  polling.value = false
  if (pollTimer) { clearInterval(pollTimer); pollTimer = null }
}

onMounted(() => { load(); loadAttachments() })
onUnmounted(stopPolling)

function statusColor(s: string) {
  const m: Record<string, string> = {
    pending: 'gray', in_progress: 'blue', review: 'yellow',
    done: 'green', blocked: 'red', decomposed: 'purple', cancelled: 'gray',
  }
  return m[s] || 'gray'
}

const roleIcons: Record<string, string> = {
  pm: '\u{1F9E0}', security: '\u{1F6E1}', debugger: '\u{1F50D}',
  frontend_dev: '\u{1F4BB}', backend_dev: '\u{2699}', tester: '\u{2705}',
  reviewer: '\u{1F4CB}', architect: '\u{1F3D7}', followup_pm: '\u{1F4DD}',
}

function stepStatusClass(step: PipelineStep) {
  if (step.success) return 'border-green-700 bg-green-950/30'
  return 'border-red-700 bg-red-950/30'
}

function stepStatusIcon(step: PipelineStep) {
  return step.success ? '\u2713' : '\u2717'
}

function stepStatusColor(step: PipelineStep) {
  return step.success ? 'text-green-400' : 'text-red-400'
}

function formatOutput(text: string | null): string {
  if (!text) return ''
  try {
    const parsed = JSON.parse(text)
    return JSON.stringify(parsed, null, 2)
  } catch {
    return text
  }
}

interface ParsedAgentOutput {
  verdict: string | null
  details: string | null
  raw: string
}

function parseAgentOutput(text: string | null): ParsedAgentOutput {
  if (!text) return { verdict: null, details: null, raw: '' }
  const verdictMatch = text.match(/##\s*Verdict\s*\n([\s\S]*?)(?=##\s*Details|$)/m)
  const detailsJsonMatch = text.match(/##\s*Details[\s\S]*?```json\n([\s\S]*?)```/)
  const verdict = verdictMatch ? verdictMatch[1].trim() : null
  let details: string | null = null
  if (detailsJsonMatch) {
    try {
      details = JSON.stringify(JSON.parse(detailsJsonMatch[1].trim()), null, 2)
    } catch {
      details = detailsJsonMatch[1].trim()
    }
  }
  return { verdict, details, raw: text }
}

async function approve() {
  if (!task.value) return
  approveLoading.value = true
  followupResults.value = []
  pendingActions.value = []
  try {
    const data: Record<string, unknown> = {
      create_followups: approveForm.value.createFollowups,
    }
    if (approveForm.value.title) {
      data.decision_title = approveForm.value.title
      data.decision_description = approveForm.value.description
      data.decision_type = approveForm.value.type
    }
    const res = await api.approveTask(props.id, data as any)
    if (res.followup_tasks?.length) {
      followupResults.value = res.followup_tasks.map(t => ({ id: t.id, title: t.title }))
    }
    if (res.pending_actions?.length) {
      pendingActions.value = res.pending_actions
    }
    if (!res.followup_tasks?.length && !res.pending_actions?.length) {
      showApprove.value = false
    }
    approveForm.value = { title: '', description: '', type: 'decision', createFollowups: true }
    await load()
  } catch (e: any) {
    error.value = e.message
  } finally {
    approveLoading.value = false
  }
}

async function resolveAction(action: PendingAction, choice: string) {
  resolvingAction.value = true
  try {
    const res = await api.resolveAction(props.id, action, choice)
    pendingActions.value = pendingActions.value.filter(a => a !== action)
    if (choice === 'manual_task' && res.result && typeof res.result === 'object' && 'id' in res.result) {
      followupResults.value.push({ id: (res.result as any).id, title: (res.result as any).title })
    }
    if (choice === 'rerun') {
      await load()
    }
  } catch (e: any) {
    error.value = e.message
  } finally {
    resolvingAction.value = false
  }
}

async function reject() {
  if (!task.value || !rejectReason.value) return
  try {
    await api.rejectTask(props.id, rejectReason.value)
    showReject.value = false
    rejectReason.value = ''
    await load()
  } catch (e: any) {
    error.value = e.message
  }
}

async function revise() {
  if (!task.value || !reviseComment.value) return
  try {
    await api.reviseTask(props.id, reviseComment.value)
    showRevise.value = false
    reviseComment.value = ''
    await load()
  } catch (e: any) {
    error.value = e.message
  }
}

async function runPipeline() {
  claudeLoginError.value = false
  pipelineStarting.value = true
  try {
    // Sync task execution_mode with current toggle state before running
    const targetMode = autoMode.value ? 'auto_complete' : 'review'
    if (task.value && task.value.execution_mode !== targetMode) {
      const updated = await api.patchTask(props.id, { execution_mode: targetMode })
      task.value = { ...task.value, ...updated }
    }
    await api.runTask(props.id)
    startPolling()
    await load()
  } catch (e: any) {
    if (e instanceof ApiError && e.code === 'claude_auth_required') {
      claudeLoginError.value = true
    } else if (e instanceof ApiError && e.code === 'task_already_running') {
      error.value = 'Pipeline уже запущен'
    } else {
      error.value = e.message
    }
  } finally {
    pipelineStarting.value = false
  }
}

const hasSteps = computed(() => (task.value?.pipeline_steps?.length ?? 0) > 0)
const isRunning = computed(() => task.value?.status === 'in_progress')
const isManualEscalation = computed(() => task.value?.brief?.task_type === 'manual_escalation')

const resolvingManually = ref(false)

async function resolveManually() {
  if (!task.value) return
  if (!confirm('Пометить задачу как решённую вручную?')) return
  resolvingManually.value = true
  try {
    const updated = await api.patchTask(props.id, { status: 'done' })
    task.value = { ...task.value, ...updated }
  } catch (e: any) {
    error.value = e.message
  } finally {
    resolvingManually.value = false
  }
}

function goBack() {
  if (window.history.length > 1) {
    router.back()
  } else if (task.value) {
    const backStatus = route.query.back_status as string | undefined
    router.push({
      path: `/project/${task.value.project_id}`,
      query: backStatus ? { status: backStatus } : undefined,
    })
  }
}

const statusChanging = ref(false)

async function changeStatus(newStatus: string) {
  if (!task.value || newStatus === task.value.status) return
  statusChanging.value = true
  try {
    const updated = await api.patchTask(props.id, { status: newStatus })
    task.value = { ...task.value, ...updated }
  } catch (e: any) {
    error.value = e.message
  } finally {
    statusChanging.value = false
  }
}

// Deploy
const deploying = ref(false)
const deployResult = ref<DeployResult | null>(null)

async function runDeploy() {
  if (!task.value) return
  deploying.value = true
  deployResult.value = null
  try {
    deployResult.value = await api.deployProject(task.value.project_id)
  } catch (e: any) {
    error.value = e.message
  } finally {
    deploying.value = false
  }
}

// Attachments
const attachments = ref<Attachment[]>([])

async function loadAttachments() {
  try {
    attachments.value = await api.getAttachments(props.id)
  } catch {}
}

// Edit modal (pending tasks only)
const showEdit = ref(false)
const editForm = ref({ title: '', briefText: '', priority: 5, acceptanceCriteria: '' })
const editLoading = ref(false)
const editError = ref('')

function getBriefText(brief: Record<string, unknown> | null): string {
  if (!brief) return ''
  if (typeof brief === 'string') return brief as string
  if ('text' in brief) return String(brief.text)
  return JSON.stringify(brief)
}

function openEdit() {
  if (!task.value) return
  editForm.value = {
    title: task.value.title,
    briefText: getBriefText(task.value.brief),
    priority: task.value.priority,
    acceptanceCriteria: task.value.acceptance_criteria ?? '',
  }
  editError.value = ''
  showEdit.value = true
}

async function saveEdit() {
  if (!task.value) return
  editLoading.value = true
  editError.value = ''
  try {
    const data: Parameters<typeof api.patchTask>[1] = {}
    if (editForm.value.title !== task.value.title) data.title = editForm.value.title
    if (editForm.value.priority !== task.value.priority) data.priority = editForm.value.priority
    const origBriefText = getBriefText(task.value.brief)
    if (editForm.value.briefText !== origBriefText) data.brief_text = editForm.value.briefText
    const origAC = task.value.acceptance_criteria ?? ''
    if (editForm.value.acceptanceCriteria !== origAC) data.acceptance_criteria = editForm.value.acceptanceCriteria
    if (Object.keys(data).length === 0) { showEdit.value = false; return }
    const updated = await api.patchTask(props.id, data)
    task.value = { ...task.value, ...updated }
    showEdit.value = false
  } catch (e: any) {
    editError.value = e.message
  } finally {
    editLoading.value = false
  }
}
</script>

<template>
  <div v-if="loading && !task" class="text-gray-500 text-sm">Loading...</div>
  <div v-else-if="error && !task" class="text-red-400 text-sm">{{ error }}</div>
  <div v-else-if="task">
    <!-- Header -->
    <div class="mb-6">
      <div class="flex items-center gap-2 mb-1">
        <button @click="goBack" class="text-gray-600 hover:text-gray-400 text-sm cursor-pointer bg-transparent border-none p-0">
          &larr; {{ task.project_id }}
        </button>
      </div>
      <div class="flex items-center gap-3 mb-2">
        <h1 class="text-xl font-bold text-gray-100">{{ task.id }}</h1>
        <span class="text-gray-400">{{ task.title }}</span>
        <Badge :text="task.status" :color="statusColor(task.status)" />
        <span v-if="task.execution_mode === 'auto_complete'"
          class="text-[10px] px-1.5 py-0.5 bg-yellow-900/40 text-yellow-400 border border-yellow-800 rounded"
          title="Auto mode: agents can write files">&#x1F513; auto</span>
        <select
          :value="task.status"
          @change="changeStatus(($event.target as HTMLSelectElement).value)"
          :disabled="statusChanging"
          class="text-xs bg-gray-800 border border-gray-700 text-gray-300 rounded px-2 py-0.5 disabled:opacity-50"
        >
          <option value="pending">pending</option>
          <option value="in_progress">in_progress</option>
          <option value="review">review</option>
          <option value="done">done</option>
          <option value="blocked">blocked</option>
          <option value="cancelled">cancelled</option>
        </select>
        <span v-if="isRunning" class="inline-block w-2 h-2 bg-blue-500 rounded-full animate-pulse"></span>
        <span class="text-xs text-gray-600">pri {{ task.priority }}</span>
      </div>
      <!-- Manual escalation context banner -->
      <div v-if="isManualEscalation" class="mb-3 px-3 py-2 border border-orange-800/60 bg-orange-950/20 rounded">
        <div class="flex items-center gap-2 mb-1">
          <span class="text-xs font-semibold text-orange-400">&#9888; Требует ручного решения</span>
          <span v-if="task.parent_task_id" class="text-xs text-gray-600">
            — эскалация из
            <router-link :to="`/task/${task.parent_task_id}`" class="text-orange-600 hover:text-orange-400">
              {{ task.parent_task_id }}
            </router-link>
          </span>
        </div>
        <p class="text-xs text-orange-300">{{ task.title }}</p>
        <p v-if="task.brief?.description" class="text-xs text-gray-400 mt-1">{{ task.brief.description }}</p>
        <p class="text-xs text-gray-600 mt-1">Автопилот не смог выполнить это автоматически. Примите меры вручную и нажмите «Решить вручную».</p>
      </div>

      <!-- Dangerous skip warning banner -->
      <div v-if="task.dangerously_skipped" class="mb-3 px-3 py-2 border border-red-700 bg-red-950/40 rounded flex items-start gap-2">
        <span class="text-red-400 text-base shrink-0">&#9888;</span>
        <div>
          <span class="text-xs font-semibold text-red-400">--dangerously-skip-permissions использовался в этой задаче</span>
          <p class="text-xs text-red-300/70 mt-0.5">Агент выполнял команды с обходом проверок разрешений. Проверьте pipeline-шаги и сделанные изменения.</p>
        </div>
      </div>

      <div v-if="task.brief && !isManualEscalation" class="text-xs text-gray-500 mb-1">
        Brief: {{ JSON.stringify(task.brief) }}
      </div>
      <div v-if="task.acceptance_criteria" class="mb-2 px-3 py-2 border border-gray-700 bg-gray-900/40 rounded">
        <div class="text-xs font-semibold text-gray-400 mb-1">Критерии приёмки</div>
        <p class="text-xs text-gray-300 whitespace-pre-wrap">{{ task.acceptance_criteria }}</p>
      </div>
      <div v-if="task.status === 'blocked' && task.blocked_reason" class="text-xs text-red-400 mb-1 bg-red-950/30 border border-red-800/40 rounded px-2 py-1">
        Blocked: {{ task.blocked_reason }}
      </div>
      <div v-if="task.assigned_role" class="text-xs text-gray-500">
        Assigned: {{ task.assigned_role }}
      </div>
    </div>

    <!-- Pipeline Graph -->
    <div v-if="hasSteps || isRunning" class="mb-6">
      <h2 class="text-sm font-semibold text-gray-300 mb-3">
        Pipeline
        <span v-if="isRunning" class="text-blue-400 text-xs font-normal ml-2 animate-pulse">running...</span>
      </h2>
      <div class="flex items-center gap-1 overflow-x-auto pb-2">
        <template v-for="(step, i) in task.pipeline_steps" :key="step.id">
          <div v-if="i > 0" class="text-gray-600 text-lg shrink-0 px-1">&rarr;</div>
          <button
            @click="selectedStep = selectedStep?.id === step.id ? null : step"
            class="border rounded-lg px-3 py-2 min-w-[120px] text-left transition-all shrink-0"
            :class="[
              stepStatusClass(step),
              selectedStep?.id === step.id ? 'ring-1 ring-blue-500' : '',
            ]"
          >
            <div class="flex items-center gap-1.5 mb-1">
              <span class="text-base">{{ roleIcons[step.agent_role] || '\u{1F916}' }}</span>
              <span class="text-xs font-medium text-gray-300">{{ step.agent_role }}</span>
              <span :class="stepStatusColor(step)" class="text-xs ml-auto">{{ stepStatusIcon(step) }}</span>
            </div>
            <div class="flex gap-2 text-[10px] text-gray-500">
              <span v-if="step.duration_seconds">{{ step.duration_seconds }}s</span>
              <span v-if="step.tokens_used">{{ step.tokens_used?.toLocaleString() }}tk</span>
              <span v-if="step.cost_usd">${{ step.cost_usd?.toFixed(3) }}</span>
            </div>
          </button>
        </template>
      </div>
    </div>

    <!-- No pipeline -->
    <div v-if="!hasSteps && !isRunning" class="mb-6 text-sm text-gray-600">
      No pipeline steps yet.
    </div>

    <!-- Live Console -->
    <LiveConsole
      v-if="task.pipeline_id"
      :pipeline-id="task.pipeline_id"
      :pipeline-status="task.status"
      class="mb-6"
    />

    <!-- Selected step output -->
    <div v-if="selectedStep && parsedSelectedOutput" class="mb-6">
      <h2 class="text-sm font-semibold text-gray-300 mb-2">
        Output: {{ selectedStep.agent_role }}
        <span class="text-xs text-gray-600 font-normal ml-2">{{ selectedStep.created_at }}</span>
      </h2>
      <div class="border border-gray-800 rounded-lg bg-gray-900/50 overflow-hidden">
        <!-- New format: verdict + collapsible details -->
        <template v-if="parsedSelectedOutput.verdict !== null">
          <div class="p-4">
            <p class="text-sm text-gray-200 leading-relaxed whitespace-pre-wrap">{{ parsedSelectedOutput.verdict }}</p>
            <details v-if="parsedSelectedOutput.details !== null" class="mt-3">
              <summary class="text-xs text-gray-500 cursor-pointer hover:text-gray-400 select-none">&darr; подробнее</summary>
              <pre class="mt-2 text-xs text-gray-500 overflow-x-auto whitespace-pre-wrap max-h-[400px] overflow-y-auto">{{ parsedSelectedOutput.details }}</pre>
            </details>
          </div>
        </template>
        <!-- Fallback: old format -->
        <template v-else>
          <pre class="p-4 text-xs text-gray-300 overflow-x-auto whitespace-pre-wrap max-h-[600px] overflow-y-auto">{{ formatOutput(selectedStep.output_summary) }}</pre>
        </template>
      </div>
    </div>

    <!-- Related Decisions -->
    <div v-if="task.related_decisions?.length" class="mb-6">
      <h2 class="text-sm font-semibold text-gray-300 mb-2">Related Decisions</h2>
      <div class="space-y-1">
        <div v-for="d in task.related_decisions" :key="d.id"
          class="px-3 py-2 border border-gray-800 rounded text-xs">
          <Badge :text="d.type" :color="d.type === 'gotcha' ? 'red' : 'blue'" />
          <span class="text-gray-300 ml-2">{{ d.title }}</span>
        </div>
      </div>
    </div>

    <!-- Attachments -->
    <div class="mb-6">
      <h2 class="text-sm font-semibold text-gray-300 mb-2">Вложения</h2>
      <AttachmentList :attachments="attachments" :task-id="props.id" @deleted="loadAttachments" />
      <AttachmentUploader :task-id="props.id" @uploaded="loadAttachments" />
    </div>

    <!-- Actions Bar -->
    <div class="sticky bottom-0 bg-gray-950 border-t border-gray-800 py-3 flex gap-3 -mx-6 px-6 mt-8">
      <div v-if="autoMode && (isRunning || task.status === 'review')"
        class="flex items-center gap-1.5 px-3 py-1.5 bg-yellow-900/20 border border-yellow-800/50 rounded text-xs text-yellow-400">
        <span class="inline-block w-2 h-2 bg-yellow-400 rounded-full animate-pulse"></span>
        Автопилот активен
      </div>
      <button v-if="task.status === 'review' && !autoMode"
        @click="showApprove = true"
        class="px-4 py-2 text-sm bg-green-900/50 text-green-400 border border-green-800 rounded hover:bg-green-900">
        &#10003; Approve
      </button>
      <button v-if="task.status === 'review' && !autoMode"
        @click="showRevise = true"
        class="px-4 py-2 text-sm bg-orange-900/50 text-orange-400 border border-orange-800 rounded hover:bg-orange-900">
        &#x1F504; Revise
      </button>
      <button v-if="(task.status === 'review' || task.status === 'in_progress') && !autoMode"
        @click="showReject = true"
        class="px-4 py-2 text-sm bg-red-900/50 text-red-400 border border-red-800 rounded hover:bg-red-900">
        &#10007; Reject
      </button>
      <button v-if="task.status === 'pending' || task.status === 'blocked' || task.status === 'review'"
        @click="toggleMode"
        class="px-3 py-2 text-sm border rounded transition-colors"
        :class="autoMode
          ? 'bg-yellow-900/30 text-yellow-400 border-yellow-800 hover:bg-yellow-900/50'
          : 'bg-gray-800/50 text-gray-400 border-gray-700 hover:bg-gray-800'"
        :title="autoMode ? 'Auto mode: agents can write files' : 'Review mode: agents read-only'">
        {{ autoMode ? '&#x1F513; Auto' : '&#x1F512; Review' }}
      </button>
      <button v-if="task.status === 'pending'"
        @click="openEdit"
        class="px-3 py-2 text-sm bg-gray-800/50 text-gray-400 border border-gray-700 rounded hover:bg-gray-800">
        &#9998; Edit
      </button>
      <button v-if="task.status === 'pending' || task.status === 'blocked'"
        @click="runPipeline"
        :disabled="polling || pipelineStarting"
        class="px-4 py-2 text-sm bg-blue-900/50 text-blue-400 border border-blue-800 rounded hover:bg-blue-900 disabled:opacity-50">
        <span v-if="polling || pipelineStarting" class="inline-block w-3 h-3 border-2 border-blue-400 border-t-transparent rounded-full animate-spin mr-1"></span>
        {{ (polling || pipelineStarting) ? 'Pipeline running...' : '&#9654; Run Pipeline' }}
      </button>
      <button v-if="isManualEscalation && task.status !== 'done' && task.status !== 'cancelled'"
        @click="resolveManually"
        :disabled="resolvingManually"
        class="px-4 py-2 text-sm bg-orange-900/50 text-orange-400 border border-orange-800 rounded hover:bg-orange-900 disabled:opacity-50">
        <span v-if="resolvingManually" class="inline-block w-3 h-3 border-2 border-orange-400 border-t-transparent rounded-full animate-spin mr-1"></span>
        {{ resolvingManually ? 'Сохраняем...' : '&#10003; Решить вручную' }}
      </button>
      <button v-if="task.status === 'done' && task.project_deploy_command"
        @click.stop="runDeploy"
        :disabled="deploying"
        class="px-4 py-2 text-sm bg-teal-900/50 text-teal-400 border border-teal-800 rounded hover:bg-teal-900 disabled:opacity-50">
        <span v-if="deploying" class="inline-block w-3 h-3 border-2 border-teal-400 border-t-transparent rounded-full animate-spin mr-1"></span>
        {{ deploying ? 'Deploying...' : '&#x1F680; Deploy' }}
      </button>
    </div>

    <!-- Claude login error banner -->
    <div v-if="claudeLoginError" class="mt-3 px-4 py-3 border border-yellow-700 bg-yellow-950/30 rounded">
      <div class="flex items-start justify-between gap-2">
        <div>
          <p class="text-sm font-semibold text-yellow-300">&#9888; Claude CLI requires login</p>
          <p class="text-xs text-yellow-200/80 mt-1">Откройте терминал и выполните:</p>
          <code class="text-xs text-yellow-400 font-mono bg-black/30 px-2 py-0.5 rounded mt-1 inline-block">claude login</code>
          <p class="text-xs text-gray-500 mt-1">После входа повторите запуск pipeline.</p>
        </div>
        <button @click="claudeLoginError = false" class="text-gray-600 hover:text-gray-400 bg-transparent border-none cursor-pointer text-xs shrink-0">✕</button>
      </div>
    </div>

    <!-- Deploy result inline block -->
    <div v-if="deployResult" class="mx-0 mt-2 p-3 rounded border text-xs font-mono"
      :class="deployResult.overall_success !== false && deployResult.success ? 'border-teal-800 bg-teal-950/30 text-teal-300' : 'border-red-800 bg-red-950/30 text-red-300'">
      <div class="flex items-center gap-2 mb-1">
        <span :class="deployResult.overall_success !== false && deployResult.success ? 'text-teal-400' : 'text-red-400'" class="font-semibold">
          {{ deployResult.overall_success !== false && deployResult.success ? 'Deploy succeeded' : 'Deploy failed' }}
        </span>
        <span class="text-gray-500">{{ deployResult.duration_seconds }}s</span>
        <button @click.stop="deployResult = null" class="ml-auto text-gray-600 hover:text-gray-400 bg-transparent border-none cursor-pointer text-xs">x</button>
      </div>
      <!-- Structured steps -->
      <div v-if="deployResult.results?.length" class="space-y-1 mt-1">
        <details v-for="step in deployResult.results" :key="step.step" class="border border-gray-700 rounded">
          <summary class="flex items-center gap-2 px-2 py-1 cursor-pointer list-none">
            <span :class="step.exit_code === 0 ? 'text-teal-400' : 'text-red-400'" class="font-semibold text-[10px]">{{ step.exit_code === 0 ? 'ok' : 'fail' }}</span>
            <span class="text-gray-300 text-[11px]">{{ step.step }}</span>
            <span class="text-gray-600 text-[10px] ml-auto">exit {{ step.exit_code }}</span>
          </summary>
          <div class="px-2 pb-2">
            <pre v-if="step.stdout" class="whitespace-pre-wrap text-gray-300 max-h-32 overflow-y-auto text-[10px]">{{ step.stdout }}</pre>
            <pre v-if="step.stderr" class="whitespace-pre-wrap text-red-400/80 max-h-32 overflow-y-auto text-[10px] mt-1">{{ step.stderr }}</pre>
          </div>
        </details>
      </div>
      <!-- Legacy output -->
      <template v-else>
        <pre v-if="deployResult.stdout" class="whitespace-pre-wrap text-gray-300 max-h-40 overflow-y-auto">{{ deployResult.stdout }}</pre>
        <pre v-if="deployResult.stderr" class="whitespace-pre-wrap text-red-400/80 max-h-40 overflow-y-auto mt-1">{{ deployResult.stderr }}</pre>
      </template>
      <!-- Dependents -->
      <div v-if="deployResult.dependents_deployed?.length" class="mt-2 border-t border-gray-700 pt-2">
        <p class="text-xs text-gray-400 font-semibold mb-1">Зависимые проекты:</p>
        <details v-for="dep in deployResult.dependents_deployed" :key="dep.project_id" class="border border-gray-700 rounded mb-1">
          <summary class="flex items-center gap-2 px-2 py-1 cursor-pointer list-none">
            <span :class="dep.success ? 'text-teal-400' : 'text-red-400'" class="font-semibold text-[10px]">{{ dep.success ? 'ok' : 'fail' }}</span>
            <span class="text-gray-300 text-[11px]">{{ dep.project_name }}</span>
          </summary>
          <div class="px-2 pb-2 space-y-1">
            <details v-for="step in dep.results" :key="step.step" class="border border-gray-800 rounded">
              <summary class="flex items-center gap-2 px-2 py-0.5 cursor-pointer list-none">
                <span :class="step.exit_code === 0 ? 'text-teal-400' : 'text-red-400'" class="text-[10px]">{{ step.exit_code === 0 ? 'ok' : 'fail' }}</span>
                <span class="text-gray-400 text-[10px]">{{ step.step }}</span>
              </summary>
              <div class="px-2 pb-1">
                <pre v-if="step.stdout" class="whitespace-pre-wrap text-gray-300 max-h-24 overflow-y-auto text-[10px]">{{ step.stdout }}</pre>
                <pre v-if="step.stderr" class="whitespace-pre-wrap text-red-400/80 max-h-24 overflow-y-auto text-[10px]">{{ step.stderr }}</pre>
              </div>
            </details>
          </div>
        </details>
      </div>
    </div>

    <!-- Approve Modal -->
    <Modal v-if="showApprove" title="Approve Task" @close="showApprove = false; followupResults = []; pendingActions = []">
      <!-- Pending permission actions -->
      <div v-if="pendingActions.length" class="space-y-3">
        <p class="text-sm text-yellow-400">Permission issues need your decision:</p>
        <div v-for="(action, i) in pendingActions" :key="i"
          class="border border-yellow-900/50 rounded-lg p-3 space-y-2">
          <p class="text-sm text-gray-300">{{ action.description }}</p>
          <div class="flex gap-2">
            <button @click="resolveAction(action, 'rerun')" :disabled="resolvingAction"
              class="px-3 py-1 text-xs bg-blue-900/50 text-blue-400 border border-blue-800 rounded hover:bg-blue-900 disabled:opacity-50">
              Rerun (skip permissions)
            </button>
            <button @click="resolveAction(action, 'manual_task')" :disabled="resolvingAction"
              class="px-3 py-1 text-xs bg-gray-800 text-gray-300 border border-gray-700 rounded hover:bg-gray-700 disabled:opacity-50">
              Create task
            </button>
            <button @click="resolveAction(action, 'skip')" :disabled="resolvingAction"
              class="px-3 py-1 text-xs bg-gray-800 text-gray-500 border border-gray-700 rounded hover:bg-gray-700 disabled:opacity-50">
              Skip
            </button>
          </div>
        </div>
      </div>
      <!-- Follow-up results -->
      <div v-if="followupResults.length && !pendingActions.length" class="space-y-3">
        <p class="text-sm text-green-400">Task approved. Created {{ followupResults.length }} follow-up tasks:</p>
        <div class="space-y-1">
          <router-link v-for="f in followupResults" :key="f.id" :to="`/task/${f.id}`"
            class="block px-3 py-2 border border-gray-800 rounded text-sm text-gray-300 hover:border-gray-600 no-underline">
            <span class="text-gray-500">{{ f.id }}</span> {{ f.title }}
          </router-link>
        </div>
        <button @click="showApprove = false; followupResults = []"
          class="w-full py-2 bg-gray-800 text-gray-300 border border-gray-700 rounded text-sm hover:bg-gray-700">
          Close
        </button>
      </div>
      <!-- Approve form -->
      <form v-if="!followupResults.length && !pendingActions.length" @submit.prevent="approve" class="space-y-3">
        <label class="flex items-center gap-2 text-sm text-gray-300 cursor-pointer">
          <input type="checkbox" v-model="approveForm.createFollowups"
            class="rounded border-gray-600 bg-gray-800 text-blue-500" />
          Create follow-up tasks from pipeline results
        </label>
        <p class="text-xs text-gray-500">Optionally record a decision:</p>
        <input v-model="approveForm.title" placeholder="Decision title (optional)"
          class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 placeholder-gray-600" />
        <textarea v-if="approveForm.title" v-model="approveForm.description" placeholder="Description"
          class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 placeholder-gray-600 resize-y" rows="2"></textarea>
        <button type="submit" :disabled="approveLoading"
          class="w-full py-2 bg-green-900/50 text-green-400 border border-green-800 rounded text-sm hover:bg-green-900 disabled:opacity-50">
          {{ approveLoading ? 'Processing...' : 'Approve &amp; mark done' }}
        </button>
      </form>
    </Modal>

    <!-- Reject Modal -->
    <Modal v-if="showReject" title="Reject Task" @close="showReject = false">
      <form @submit.prevent="reject" class="space-y-3">
        <textarea v-model="rejectReason" placeholder="Why are you rejecting this?" rows="3" required
          class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 placeholder-gray-600 resize-y"></textarea>
        <button type="submit"
          class="w-full py-2 bg-red-900/50 text-red-400 border border-red-800 rounded text-sm hover:bg-red-900">
          Reject &amp; return to pending
        </button>
      </form>
    </Modal>

    <!-- Revise Modal -->
    <Modal v-if="showRevise" title="&#x1F504; Revise Task" @close="showRevise = false">
      <form @submit.prevent="revise" class="space-y-3">
        <p class="text-xs text-gray-500">Опишите, что доработать или уточнить агенту. Задача вернётся в работу с вашим комментарием.</p>
        <textarea v-model="reviseComment" placeholder="Что доработать / уточнить..." rows="4" required
          class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 placeholder-gray-600 resize-y"></textarea>
        <button type="submit"
          class="w-full py-2 bg-orange-900/50 text-orange-400 border border-orange-800 rounded text-sm hover:bg-orange-900">
          &#x1F504; Отправить на доработку
        </button>
      </form>
    </Modal>

    <!-- Edit Modal (pending tasks only) -->
    <Modal v-if="showEdit" title="Edit Task" @close="showEdit = false">
      <form @submit.prevent="saveEdit" class="space-y-3">
        <div>
          <label class="block text-xs text-gray-500 mb-1">Title</label>
          <input v-model="editForm.title" required
            class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 placeholder-gray-600" />
        </div>
        <div>
          <label class="block text-xs text-gray-500 mb-1">Brief</label>
          <textarea v-model="editForm.briefText" rows="4" placeholder="Task description..."
            class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 placeholder-gray-600 resize-y"></textarea>
        </div>
        <div>
          <label class="block text-xs text-gray-500 mb-1">Priority (1–10)</label>
          <input v-model.number="editForm.priority" type="number" min="1" max="10" required
            class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200" />
        </div>
        <div>
          <label class="block text-xs text-gray-500 mb-1">Критерии приёмки</label>
          <textarea v-model="editForm.acceptanceCriteria" rows="3"
            placeholder="Что должно быть на выходе? Какой результат считается успешным?"
            class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 placeholder-gray-600 resize-y"></textarea>
        </div>
        <p v-if="editError" class="text-red-400 text-xs">{{ editError }}</p>
        <button type="submit" :disabled="editLoading"
          class="w-full py-2 bg-blue-900/50 text-blue-400 border border-blue-800 rounded text-sm hover:bg-blue-900 disabled:opacity-50">
          {{ editLoading ? 'Saving...' : 'Save' }}
        </button>
      </form>
    </Modal>
  </div>
</template>
