<script setup>
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import {
  Package, RefreshCw, Trash2, LoaderCircle, Check, CircleX, Terminal,
  FolderOpen, Copy, Eraser
} from 'lucide-vue-next'
import { call, on, copyText } from '../api'
import { useAppStore } from '../store'

const { t } = useI18n()
const store = useAppStore()
const route = useRoute()
const router = useRouter()

const tasks = ref([])
const selectedId = ref('')
const detail = ref(null)
const loading = ref(false)
const logEl = ref(null)
const stickBottom = ref(true)
let offTask = null
let offLog = null

const selected = computed(() => tasks.value.find(x => x.id === selectedId.value) || null)
const logLines = computed(() => detail.value?.logs || [])

function statusLabel(s) {
  if (s === 'running') return t('packTaskRunning')
  if (s === 'done') return t('packTaskDone')
  return t('packTaskFailed')
}
function fmtTime(s) {
  if (!s) return ''
  return String(s).replace('T', ' ').slice(5, 19)
}
function lineClass(line) {
  const s = String(line || '')
  if (s.startsWith('✗') || /error|failed|失败/i.test(s)) return 'err'
  if (s.startsWith('✓') || /success|完成|done/i.test(s)) return 'ok'
  if (s.startsWith('▶') || s.startsWith('$') || s.startsWith('cwd:') || s.startsWith('pid=')) return 'meta'
  return ''
}

async function loadList() {
  loading.value = true
  try { tasks.value = await call('ListLocalPackTasks') || [] } catch { tasks.value = [] }
  loading.value = false
  if (!selectedId.value && tasks.value.length) {
    selectedId.value = tasks.value[0].id
  } else if (selectedId.value && !tasks.value.some(x => x.id === selectedId.value)) {
    selectedId.value = tasks.value[0]?.id || ''
  }
}

async function loadDetail(id) {
  if (!id) { detail.value = null; return }
  try {
    detail.value = await call('GetLocalPackTask', id)
    await scrollLog(true)
  } catch {
    detail.value = null
  }
}

function selectTask(id) {
  selectedId.value = id
  router.replace({ path: '/pack-tasks', query: id ? { id } : {} })
}

async function clearDone() {
  try {
    tasks.value = await call('ClearFinishedLocalPackTasks') || []
    if (selectedId.value && !tasks.value.some(x => x.id === selectedId.value)) {
      selectedId.value = tasks.value[0]?.id || ''
      router.replace({ path: '/pack-tasks', query: selectedId.value ? { id: selectedId.value } : {} })
    }
  } catch { /* ignore */ }
}

async function dismiss(id) {
  try {
    tasks.value = await call('DismissLocalPackTask', id) || []
    if (selectedId.value === id) {
      selectedId.value = tasks.value[0]?.id || ''
      router.replace({ path: '/pack-tasks', query: selectedId.value ? { id: selectedId.value } : {} })
    }
  } catch { /* ignore */ }
}

async function copyLogs() {
  const text = (detail.value?.logs || []).join('\n')
  try {
    await copyText(text)
    store.showToast({ type: 'success', text: t('packLogCopied') })
  } catch {
    store.showToast({ type: 'error', text: t('copyFailed') })
  }
}

function onLogScroll() {
  const el = logEl.value
  if (!el) return
  stickBottom.value = el.scrollHeight - el.scrollTop - el.clientHeight < 48
}

async function scrollLog(force) {
  await nextTick()
  const el = logEl.value
  if (!el) return
  if (force || stickBottom.value) el.scrollTop = el.scrollHeight
}

watch(selectedId, id => { loadDetail(id) })

watch(() => route.query.id, id => {
  const v = String(id || '')
  if (v && v !== selectedId.value) selectedId.value = v
})

onMounted(async () => {
  if (route.query.id) selectedId.value = String(route.query.id)
  await loadList()
  if (selectedId.value) await loadDetail(selectedId.value)
  offTask = on('pack:task', async ev => {
    await loadList()
    const d = Array.isArray(ev) ? ev[0] : ev
    if (d?.id && d.id === selectedId.value && detail.value?.id === d.id) {
      detail.value = {
        ...detail.value,
        status: d.status || detail.value.status,
        pid: d.pid || detail.value.pid,
        error: d.error ?? detail.value.error,
        endedAt: d.endedAt || detail.value.endedAt
      }
    }
  })
  offLog = on('pack:log', ev => {
    const d = Array.isArray(ev) ? ev[0] : ev
    if (!d?.taskId || d.taskId !== selectedId.value) return
    if (!detail.value || detail.value.id !== d.taskId) return
    detail.value = { ...detail.value, logs: [...(detail.value.logs || []), d.line] }
    scrollLog(false)
  })
})
onUnmounted(() => {
  offTask?.()
  offLog?.()
})
</script>

<template>
  <div class="page pack-tasks-page">
    <header class="page-head sticky-head lp-head">
      <div class="lp-head-top">
        <div>
          <h1>{{ t('packTasksPage') }}</h1>
          <p>{{ t('packTasksPageSub') }}</p>
        </div>
        <div class="lp-tools">
          <button class="btn secondary" :disabled="loading" @click="loadList"><RefreshCw :class="{ spinning: loading }" />{{ t('lpRefresh') }}</button>
          <button class="btn secondary" :disabled="!tasks.some(x => x.status !== 'running')" @click="clearDone"><Trash2 />{{ t('packTasksClear') }}</button>
        </div>
      </div>
    </header>

    <div class="pack-tasks-layout">
      <aside class="pack-tasks-side">
        <div v-if="!tasks.length" class="lp-empty">{{ t('packTasksEmpty') }}</div>
        <button
          v-for="x in tasks"
          :key="x.id"
          type="button"
          class="pack-task-row"
          :class="[x.status, { on: x.id === selectedId }]"
          @click="selectTask(x.id)"
        >
          <span class="pack-task-st">
            <LoaderCircle v-if="x.status === 'running'" class="spin" />
            <Check v-else-if="x.status === 'done'" />
            <CircleX v-else />
          </span>
          <div class="pack-task-main">
            <b>{{ x.title || x.cmd }}</b>
            <small>{{ statusLabel(x.status) }} · {{ fmtTime(x.startedAt) }}</small>
            <code v-if="x.cmd !== x.title">{{ x.cmd }}</code>
          </div>
          <button v-if="x.status !== 'running'" type="button" class="pack-task-rm" :title="t('delete')" @click.stop="dismiss(x.id)"><Trash2 /></button>
        </button>
      </aside>

      <section class="pack-tasks-console card">
        <template v-if="selected || detail">
          <header class="pack-console-head">
            <div>
              <h2><Terminal />{{ detail?.title || selected?.title || t('packTasks') }}</h2>
              <p>
                <em :class="detail?.status || selected?.status">{{ statusLabel(detail?.status || selected?.status) }}</em>
                <span v-if="detail?.pid || selected?.pid">PID {{ detail?.pid || selected?.pid }}</span>
                <span v-if="detail?.startedAt">{{ fmtTime(detail.startedAt) }}</span>
              </p>
            </div>
            <div class="pack-console-acts">
              <button type="button" class="btn secondary" :disabled="!logLines.length" @click="copyLogs"><Copy />{{ t('packLogCopy') }}</button>
            </div>
          </header>
          <div v-if="detail?.dir || detail?.cmd" class="pack-console-meta">
            <span v-if="detail.dir" :title="detail.dir"><FolderOpen />{{ detail.dir }}</span>
            <code v-if="detail.cmd">$ {{ detail.cmd }}</code>
          </div>
          <div ref="logEl" class="pack-console-body" @scroll="onLogScroll">
            <pre v-for="(line, i) in logLines" :key="i" class="pack-console-line" :class="lineClass(line)">{{ line }}</pre>
            <div v-if="!logLines.length" class="pack-console-empty">{{ t('packLogEmpty') }}</div>
          </div>
          <p v-if="detail?.error" class="pack-console-err">{{ detail.error }}</p>
        </template>
        <div v-else class="pack-console-placeholder">
          <Eraser />
          <p>{{ t('packTasksPick') }}</p>
        </div>
      </section>
    </div>
  </div>
</template>
