<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useWorkflowStore } from '../../stores/workflow'
import { NButton, NIcon, NEmpty, NSpin, NTag, NPopconfirm, useMessage } from 'naive-ui'
import { AddOutline, CreateOutline, TrashOutline, PricetagsOutline, ReloadOutline, SearchOutline, CubeOutline, BookmarksOutline, SparklesOutline } from '@vicons/ionicons5'
import { getWfCategoryTree, createWfCategory, updateWfCategory, deleteWfCategory as deleteCategoryApi } from '../../api/wfCategory'
import { setWorkflowCategory, getWorkflows, generateWorkflowDescription, updateWorkflowDescription } from '../../api/workflow'
import { useConfirmDelete } from '../../composables/useConfirmDelete'
import { parseNodes } from '../../utils/workflowNode'
import NodeThumbnail from '../../components/workflow/NodeThumbnail.vue'
import TagSelector from '../../components/tag/TagSelector.vue'
import CategoryPicker from '../../components/skill/CategoryPicker.vue'
import CategoryTree from '../../components/skill/CategoryTree.vue'
import TemplatePicker from '../../components/workflow/TemplatePicker.vue'

const router = useRouter()
const wfStore = useWorkflowStore()
const message = useMessage()
const confirmDelete = useConfirmDelete()

// 标签选择器状态
const showTagSelector = ref(false)
const taggingWf = ref(null)

// 分类选择器状态
const showCategoryPicker = ref(false)
const categorizingWf = ref(null)

// 模板选择器状态
const showTemplatePicker = ref(false)

function openCategoryPicker(wf) {
  categorizingWf.value = wf
  showCategoryPicker.value = true
}

async function onCategorySaved(categoryId) {
  if (!categorizingWf.value) return
  try {
    await setWorkflowCategory(categorizingWf.value.name, categoryId)
    await wfStore.fetchList()
    await loadCategories()
    message.success('分类已更新')
  } catch (err) {
    message.error(err.response?.data?.message || '设置分类失败')
  } finally {
    categorizingWf.value = null
  }
}

function openTagSelector(wf) {
  taggingWf.value = wf
  showTagSelector.value = true
}

function createAndEdit() {
  showTemplatePicker.value = true
}

function handleTemplateSelect(tpl) {
  router.push(`/orchestration/edit?templateId=${tpl.id}`)
}

function editWorkflow(name) {
  router.push(`/orchestration/edit/${name}`)
}

function handleDelete(wf) {
  confirmDelete({
    name: wf.displayName || wf.name,
    itemType: '智能体',
    onConfirm: async () => {
      try {
        await wfStore.remove(wf.name)
        loadCategories()
        message.success('工作流已删除')
      } catch (e) {
        message.error(e.response?.data?.message || '删除失败')
      }
    },
  })
}

async function onTagsSaved() {
  await wfStore.fetchList()
  message.success('标签已更新')
}

// ==================== 批量 AI 生成描述 ====================
const batchGenerating = ref(false)
const batchProgress = ref({ done: 0, total: 0 })

/**
 * 对所有智能体执行 AI 描述生成：
 * - 描述已清晰的跳过（skipped）
 * - 新生成的描述自动保存（updateWorkflowDescription，不建版本快照）
 * 前端逐个串行调用，按钮上实时显示进度。
 */
async function handleBatchGenerateDesc() {
  if (batchGenerating.value) return
  batchGenerating.value = true
  batchProgress.value = { done: 0, total: 0 }
  let saved = 0, skipped = 0, failed = 0
  const failedNames = []
  try {
    // 拿全量列表（不走分页）
    const { data } = await getWorkflows({ page: 1, size: 9999 })
    const all = data.content || []
    if (!all.length) {
      message.info('暂无智能体')
      return
    }
    batchProgress.value = { done: 0, total: all.length }
    for (const wf of all) {
      try {
        const res = await generateWorkflowDescription(wf.name)
        const d = res.data || {}
        if (d.skipped) {
          skipped++
        } else if (d.description) {
          await updateWorkflowDescription(wf.name, d.description)
          saved++
        } else {
          failed++
          failedNames.push(wf.displayName || wf.name)
        }
      } catch (e) {
        failed++
        failedNames.push(wf.displayName || wf.name)
      }
      batchProgress.value = { done: batchProgress.value.done + 1, total: all.length }
    }
    const parts = []
    if (saved) parts.push(`${saved} 个已生成并保存`)
    if (skipped) parts.push(`${skipped} 个描述已清晰跳过`)
    if (failed) {
      parts.push(`${failed} 个失败（${failedNames.slice(0, 3).join('、')}${failedNames.length > 3 ? ' 等' : ''}）`)
    }
    message[failed ? 'warning' : 'success'](`批量生成完成：${parts.join('，') || '无变更'}`, { duration: 8000 })
    await wfStore.fetchList()
  } catch (e) {
    message.error(e.message || '批量生成描述失败')
  } finally {
    batchGenerating.value = false
  }
}

// ==================== 分类树 ====================
const categories = ref([])
const expandedIds = ref(new Set())
const editingId = ref(null)
const editingName = ref('')
const addingParentId = ref(undefined)
const addingName = ref('')

async function loadCategories() {
  try {
    const res = await getWfCategoryTree()
    categories.value = res.data || []
  } catch (err) {
    message.error('加载分类失败')
  }
}

function toggleExpand(id) {
  if (expandedIds.value.has(id)) {
    expandedIds.value.delete(id)
  } else {
    expandedIds.value.add(id)
  }
}

function selectCategory(categoryId) {
  if (wfStore.selectedCategoryId === categoryId) {
    wfStore.setCategory(null)
  } else {
    wfStore.setCategory(categoryId)
  }
}

function startAdd(parentId) {
  addingParentId.value = parentId
  addingName.value = ''
}

function cancelAdd() {
  addingParentId.value = undefined
  addingName.value = ''
}

async function confirmAdd() {
  if (!addingName.value.trim()) return
  try {
    await createWfCategory({ parentId: addingParentId.value, name: addingName.value.trim() })
    await loadCategories()
    if (addingParentId.value != null) {
      expandedIds.value.add(addingParentId.value)
    }
    cancelAdd()
  } catch (err) {
    message.error(err.message || '创建失败')
  }
}

function startEdit({ id, name }) {
  editingId.value = id
  editingName.value = name
}

function cancelEdit() {
  editingId.value = null
  editingName.value = ''
}

async function confirmEdit() {
  if (!editingName.value.trim()) return
  try {
    await updateWfCategory(editingId.value, { name: editingName.value.trim() })
    await loadCategories()
    cancelEdit()
  } catch (err) {
    message.error(err.message || '更新失败')
  }
}

function handleDeleteCategory({ id, name }) {
  confirmDelete({
    name,
    itemType: '分类',
    content: `确定要删除分类「${name}」吗？该分类下的智能体将变为未分类。`,
    onConfirm: async () => {
      try {
        await deleteCategoryApi(id)
        await loadCategories()
        if (wfStore.selectedCategoryId === id) {
          wfStore.setCategory(null)
        } else {
          wfStore.fetchList()
        }
        message.success('删除成功')
      } catch (err) {
        message.error(err.message || '删除失败')
      }
    },
  })
}

// ==================== 工具函数 ====================
// 节点配置（颜色映射、parseNodes）见 utils/workflowNode.js


function formatTime(dt) {
  if (!dt) return ''
  return dt.replace('T', ' ').slice(0, 16)
}

// 搜索防抖
let searchTimer = null
function onSearchInput(value) {
  clearTimeout(searchTimer)
  searchTimer = setTimeout(() => {
    wfStore.setSearch(value)
  }, 300)
}

// ==================== 初始化 ====================

onMounted(() => {
  wfStore.fetchList()
  loadCategories()
})
</script>

<template>
  <div class="workflow-list-page">
    <div class="main-layout">
      <!-- 左侧分类树 -->
      <div class="sidebar">
        <div class="sidebar-header">
          <span class="sidebar-title">分类</span>
          <button class="icon-btn" @click="startAdd(null)" title="新建根分类">
            <n-icon size="16"><AddOutline /></n-icon>
          </button>
        </div>

        <div class="category-list">
          <div
            class="all-item"
            :class="{ active: !wfStore.selectedCategoryId }"
            @click="selectCategory(null)"
          >
            <span class="cat-name">全部智能体</span>
            <span class="cat-count">{{ wfStore.unfilteredTotal }}</span>
          </div>

          <CategoryTree
            :nodes="categories"
            :level="0"
            :selected-id="wfStore.selectedCategoryId"
            :expanded-ids="expandedIds"
            :editing-id="editingId"
            v-model:editing-name="editingName"
            :adding-parent-id="addingParentId"
            v-model:adding-name="addingName"
            @select="selectCategory"
            @toggle="toggleExpand"
            @add="startAdd"
            @delete="handleDeleteCategory"
            @edit-start="startEdit"
            @edit-confirm="confirmEdit"
            @edit-cancel="cancelEdit"
            @add-confirm="confirmAdd"
            @add-cancel="cancelAdd"
          />

          <div v-if="addingParentId === null" class="root-adding">
            <input
              class="inline-input"
              v-model="addingName"
              placeholder="输入分类名称"
              @keyup.enter="confirmAdd"
              @keyup.escape="cancelAdd"
              @blur="cancelAdd"
              autofocus
            />
          </div>
        </div>
      </div>

      <!-- 右侧内容 -->
      <div class="content">
        <!-- 工具栏 -->
        <div class="toolbar">
          <div class="toolbar-left">
            <div class="search-box">
              <n-icon size="16" class="search-icon"><SearchOutline /></n-icon>
              <input
                class="search-input"
                :value="wfStore.searchKeyword"
                @input="onSearchInput($event.target.value)"
                placeholder="搜索智能体名称或描述..."
              />
            </div>
            <span class="skill-count">
              共 <span class="count-num">{{ wfStore.total }}</span> 个智能体
            </span>
          </div>
          <div class="toolbar-right">
            <n-popconfirm @positive-click="handleBatchGenerateDesc">
              <template #trigger>
                <n-button size="small" :disabled="batchGenerating">
                  <template #icon><n-icon><SparklesOutline /></n-icon></template>
                  {{ batchGenerating ? `生成中 ${batchProgress.done}/${batchProgress.total}…` : '批量生成描述' }}
                </n-button>
              </template>
              将对所有智能体执行 AI 描述生成：描述已清晰的会跳过，新生成的描述会自动保存。确认继续？
            </n-popconfirm>
            <n-button size="small" @click="wfStore.fetchList(); loadCategories()">
              <template #icon><n-icon><ReloadOutline /></n-icon></template>
              刷新
            </n-button>
            <n-button size="small" @click="router.push('/templates')">
              <template #icon><n-icon><CubeOutline /></n-icon></template>
              模板管理
            </n-button>
            <n-button size="small" type="primary" @click="createAndEdit">
              <template #icon><n-icon><AddOutline /></n-icon></template>
              创建智能体
            </n-button>
          </div>
        </div>

        <!-- 加载状态 -->
        <div v-if="wfStore.loading && wfStore.workflows.length === 0" class="loading-area">
          <n-spin size="medium" />
        </div>

        <!-- 空状态 -->
        <div v-else-if="!wfStore.workflows.length" class="empty-area">
          <n-empty description="暂无智能体，点击上方按钮创建">
            <template #extra>
              <n-button type="primary" @click="createAndEdit">创建智能体</n-button>
            </template>
          </n-empty>
        </div>

        <!-- 卡片网格 -->
        <div v-else class="workflow-grid">
          <div
            v-for="(wf, index) in wfStore.workflows"
            :key="wf.name"
            class="workflow-card glow-border"
            :style="{ animationDelay: `${index * 60}ms` }"
            @click="editWorkflow(wf.name)"
          >
            <div class="card-glow-bg"></div>
            <div class="card-content">
              <div class="card-header">
                <div class="card-title-wrap">
                  <h3 class="card-title">{{ wf.displayName || wf.name }}</h3>
                  <span class="card-name" :title="wf.name">{{ wf.name }}</span>
                </div>
                <div class="card-actions">
                  <button class="action-btn tag-btn" @click.stop="openTagSelector(wf)" title="标签">
                    <n-icon size="14"><PricetagsOutline /></n-icon>
                  </button>
                  <button class="action-btn category-btn" @click.stop="openCategoryPicker(wf)" title="分类">
                    <n-icon size="14"><BookmarksOutline /></n-icon>
                  </button>
                  <button class="action-btn edit-btn" @click.stop="editWorkflow(wf.name)" title="编辑">
                    <n-icon size="14"><CreateOutline /></n-icon>
                  </button>
                  <button class="action-btn delete-btn" @click.stop="handleDelete(wf)" title="删除">
                    <n-icon size="14"><TrashOutline /></n-icon>
                  </button>
                </div>
              </div>

              <p v-if="wf.description" class="card-desc">{{ wf.description }}</p>

              <div class="card-thumbnail">
                <NodeThumbnail :graph-data="wf.graphData" :height="72" />
              </div>

              <div v-if="wf.tags && wf.tags.length" class="card-tags">
                <n-tag
                  v-for="tag in wf.tags"
                  :key="tag.tagId"
                  size="small"
                  :bordered="false"
                  type="info"
                >
                  {{ tag.tagName }}
                </n-tag>
              </div>

              <div class="card-footer">
                <span class="card-time">{{ formatTime(wf.createdAt) }}</span>
                <span class="node-count">{{ parseNodes(wf.graphData).length }} 个节点</span>
              </div>
            </div>
          </div>
        </div>

        <!-- 分页 -->
        <div v-if="wfStore.totalPages > 1" class="pagination">
          <button
            class="page-btn"
            :disabled="wfStore.currentPage <= 1"
            @click="wfStore.setPage(wfStore.currentPage - 1)"
          >上一页</button>
          <template v-for="p in wfStore.totalPages" :key="p">
            <button
              v-if="p === 1 || p === wfStore.totalPages || Math.abs(p - wfStore.currentPage) <= 1"
              class="page-btn"
              :class="{ active: p === wfStore.currentPage }"
              @click="wfStore.setPage(p)"
            >{{ p }}</button>
            <span v-else-if="Math.abs(p - wfStore.currentPage) === 2" class="page-ellipsis">...</span>
          </template>
          <button
            class="page-btn"
            :disabled="wfStore.currentPage >= wfStore.totalPages"
            @click="wfStore.setPage(wfStore.currentPage + 1)"
          >下一页</button>
        </div>
      </div>
    </div>

    <!-- 标签选择器 -->
    <TagSelector
      v-model:show="showTagSelector"
      entity-type="workflow"
      :entity-id="taggingWf?.name ? String(taggingWf.name) : ''"
      :selected-tag-ids="taggingWf?.tags?.map(t => t.tagId) || []"
      @saved="onTagsSaved"
    />

    <!-- 分类选择器 -->
    <CategoryPicker
      v-model:show="showCategoryPicker"
      category-type="workflow"
      :selected-id="categorizingWf?.categoryId || null"
      @confirm="onCategorySaved"
    />

    <!-- 模板选择器 -->
    <TemplatePicker
      v-model:show="showTemplatePicker"
      @select="handleTemplateSelect"
    />
  </div>
</template>

<style scoped>
.workflow-list-page {
  height: 100%;
  overflow: hidden;
}

.main-layout {
  display: flex;
  gap: 24px;
  height: 100%;
}

/* ==================== 左侧分类树 ==================== */
.sidebar {
  width: 240px;
  min-width: 240px;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 16px 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px 12px;
  border-bottom: 1px solid rgba(56, 189, 248, 0.06);
}

.sidebar-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary);
}

.category-list {
  flex: 1;
  overflow-y: auto;
  padding: 8px 0;
}

.all-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 16px;
  cursor: pointer;
  transition: all 0.15s;
  min-height: 32px;
}

.all-item:hover {
  background: rgba(37, 99, 235, 0.06);
}

.all-item.active {
  background: rgba(37, 99, 235, 0.12);
}

.all-item.active .cat-name {
  color: var(--color-accent);
  font-weight: 500;
}

.cat-name {
  font-size: 13px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.cat-count {
  font-size: 11px;
  color: var(--text-muted);
  background: rgba(100, 116, 139, 0.1);
  padding: 1px 6px;
  border-radius: 8px;
  min-width: 20px;
  text-align: center;
}

.icon-btn {
  background: none;
  border: none;
  color: var(--text-tertiary);
  cursor: pointer;
  padding: 4px;
  border-radius: 4px;
  display: flex;
  align-items: center;
  transition: all 0.15s;
}

.icon-btn:hover {
  color: var(--color-accent);
  background: rgba(37, 99, 235, 0.1);
}

.root-adding {
  padding: 6px 16px;
}

.inline-input {
  background: rgba(37, 99, 235, 0.08);
  border: 1px solid rgba(37, 99, 235, 0.2);
  border-radius: 4px;
  padding: 2px 8px;
  font-size: 13px;
  color: var(--text-primary);
  outline: none;
  width: 100%;
  font-family: inherit;
}

.inline-input:focus {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.15);
}

/* ==================== 右侧内容 ==================== */
.content {
  flex: 1;
  min-width: 0;
  overflow-y: auto;
  padding-right: 4px;
}

.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--bg-primary);
  padding-bottom: 12px;
}

.toolbar-left {
  display: flex;
  align-items: center;
  gap: 16px;
}

.search-box {
  position: relative;
  width: 280px;
}

.search-icon {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-muted);
}

.search-input {
  width: 100%;
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  padding: 8px 12px 8px 32px;
  font-size: 13px;
  color: var(--text-primary);
  outline: none;
  transition: border-color 0.2s;
  font-family: inherit;
}

.search-input:focus {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.15);
}

.search-input::placeholder {
  color: var(--text-muted);
}

.skill-count {
  font-size: 14px;
  color: var(--text-secondary);
}

.count-num {
  color: var(--color-accent);
  font-weight: 600;
}

.toolbar-right {
  display: flex;
  align-items: center;
  gap: 8px;
}

.loading-area, .empty-area {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 300px;
}

/* 卡片网格 */
.workflow-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 20px;
}

.workflow-card {
  position: relative;
  border-radius: var(--radius-lg);
  background: var(--bg-card);
  backdrop-filter: blur(12px);
  border: 1px solid var(--border-color);
  transition: all var(--transition-normal);
  overflow: hidden;
  cursor: pointer;
}

.workflow-card:hover {
  background: var(--bg-card-hover);
  border-color: var(--border-color-hover);
  box-shadow: var(--shadow-card-hover);
  transform: translateY(-4px);
}

.card-glow-bg {
  position: absolute;
  top: -50%;
  left: -50%;
  width: 200%;
  height: 200%;
  background: radial-gradient(circle at 30% 30%, rgba(37, 99, 235, 0.06) 0%, transparent 60%);
  pointer-events: none;
  transition: opacity var(--transition-normal);
  opacity: 0;
}

.workflow-card:hover .card-glow-bg {
  opacity: 1;
}

.card-content {
  position: relative;
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  z-index: 1;
}

.card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.card-title-wrap {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.card-title {
  font-size: 16px;
  font-weight: 600;
  color: var(--text-primary);
  line-height: 1.4;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-name {
  font-size: 11px;
  color: var(--text-tertiary, #888);
  font-family: ui-monospace, 'Cascadia Code', Menlo, monospace;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-actions {
  display: flex;
  gap: 4px;
  opacity: 0;
  transition: opacity var(--transition-fast);
  flex-shrink: 0;
}

.workflow-card:hover .card-actions {
  opacity: 1;
}

.action-btn {
  width: 28px;
  height: 28px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: all var(--transition-fast);
}

.edit-btn {
  background: rgba(37, 99, 235, 0.1);
  color: var(--color-primary-light);
}

.edit-btn:hover {
  background: rgba(37, 99, 235, 0.2);
}

.delete-btn {
  background: rgba(239, 68, 68, 0.1);
  color: var(--color-danger);
}

.delete-btn:hover {
  background: rgba(239, 68, 68, 0.2);
}

.tag-btn {
  background: rgba(34, 197, 94, 0.1);
  color: #22c55e;
}

.tag-btn:hover {
  background: rgba(34, 197, 94, 0.2);
}

.category-btn {
  background: rgba(168, 85, 247, 0.1);
  color: #a855f7;
}

.category-btn:hover {
  background: rgba(168, 85, 247, 0.2);
}

.card-desc {
  font-size: 13px;
  color: var(--text-secondary);
  line-height: 1.6;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin: 0;
}

.card-thumbnail {
  padding: 12px;
  background: rgba(15, 23, 42, 0.3);
  border-radius: var(--radius-sm);
  border: 1px solid rgba(56, 189, 248, 0.06);
}

.card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.card-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 4px;
  padding-top: 12px;
  border-top: 1px solid rgba(56, 189, 248, 0.06);
}

.card-time {
  font-size: 12px;
  color: var(--text-tertiary);
}

.node-count {
  font-size: 11px;
  color: var(--text-muted);
  background: rgba(100, 116, 139, 0.1);
  padding: 2px 8px;
  border-radius: 8px;
}

/* 分页 */
.pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-top: 32px;
  padding-top: 20px;
  border-top: 1px solid rgba(56, 189, 248, 0.06);
}

.page-btn {
  background: var(--bg-card);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-sm);
  padding: 6px 14px;
  font-size: 13px;
  color: var(--text-secondary);
  cursor: pointer;
  transition: all 0.15s;
  font-family: inherit;
}

.page-btn:hover:not(:disabled) {
  border-color: var(--color-accent);
  color: var(--color-accent);
}

.page-btn.active {
  background: var(--color-accent);
  border-color: var(--color-accent);
  color: #fff;
}

.page-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.page-ellipsis {
  color: var(--text-muted);
  padding: 0 4px;
}
</style>
