<template>
  <el-drawer
    v-model="visible"
    title="流程详情"
    direction="rtl"
    size="55%"
    :close-on-click-modal="false"
    :destroy-on-close="true"
    @closed="handleClose"
  >
    <div v-loading="loading" class="detail-content">
      <FilePreview v-model="fileUpload.previewVisible" :url="fileUpload.previewUrl" />
      <!-- 流程基本信息 -->
      <div class="info-section">
        <el-descriptions :column="3" size="small" border>
          <el-descriptions-item label="流程名称">{{ progress?.definition?.name }}</el-descriptions-item>
          <el-descriptions-item label="实例编号">{{ progress?.instance?.instanceNo || progress?.instance?.id }}</el-descriptions-item>
          <el-descriptions-item label="状态">
            <el-tag :type="instanceStatusTagType(progress?.instance?.status)">
              {{ instanceStatusText(progress?.instance?.status) }}
            </el-tag>
          </el-descriptions-item>
          <el-descriptions-item label="剩余节点">
            <el-tag type="warning">{{ progress?.remainingNodeCount || 0 }} 个待审批</el-tag>
          </el-descriptions-item>
          <el-descriptions-item label="发起时间">{{ progress?.instance?.startTime }}</el-descriptions-item>
          <el-descriptions-item label="结束时间">{{ progress?.instance?.endTime || '-' }}</el-descriptions-item>
        </el-descriptions>
      </div>

      <!-- 表单数据 -->
      <div v-if="formDataDisplay" class="form-data-section">
        <div class="section-title">
          <h4>表单数据</h4>
          <el-button v-if="canEditForm && !formEditing" type="primary" size="small" link @click="startEditForm">补充/编辑材料</el-button>
        </div>
        <template v-if="formEditing">
          <FlowFormFields
            ref="formFieldsRef"
            :definition="progress?.definition"
            v-model="editFormData"
          />
          <div class="form-edit-actions">
            <el-button size="small" @click="cancelEditForm">取消</el-button>
            <el-button type="primary" size="small" :loading="savingForm" @click="saveFormData">保存</el-button>
          </div>
        </template>
        <FormDataDisplay
          v-else
          :form-schema="progress?.definition?.formSchema"
          :form-data="progress?.instance?.formData"
        />
      </div>

      <!-- TODO: 接入OSS后重新启用附件功能 -->
      <!-- 附件列表 -->
      <div v-if="false" class="attachment-section">
        <h4>附件列表</h4>
        <div v-if="attachments.length > 0" class="attachment-list">
          <div v-for="att in attachments" :key="att.id" class="attachment-item">
            <el-link type="primary" @click="fileUpload.openPreview(att.fileUrl)">
              <el-icon><Document /></el-icon>
              <span class="attachment-name" :title="att.fileName">{{ att.fileName }}</span>
            </el-link>
            <span class="attachment-meta">
              {{ att.nodeName || '发起' }}
              <template v-if="att.uploaderName">· {{ att.uploaderName }}</template>
              <template v-if="att.createTime">· {{ att.createTime }}</template>
            </span>
            <el-image
              v-if="isImage(att.fileUrl)"
              :src="getFileUrl(att.fileUrl)"
              :preview-src-list="imagePreviewList"
              fit="cover"
              style="width: 60px; height: 60px; margin-left: 8px;"
            />
          </div>
        </div>
        <el-empty v-else description="暂无附件" :image-size="60" style="padding: 10px 0;" />
      </div>

      <el-divider />

      <div class="detail-body">
        <!-- 左侧：流程节点时间线 -->
        <div class="timeline-section">
          <h4>流程进度</h4>
          <el-timeline>
            <el-timeline-item
              v-for="node in progress?.nodes"
              :key="node.nodeId"
              :type="timelineType(node.status)"
              :icon="timelineIcon(node.status)"
              :color="timelineColor(node.status)"
            >
              <div class="node-item" :class="{ 'current-node': node.status === 'current' }">
                <div class="node-title">
                  <span class="node-name">{{ node.nodeName }}</span>
                  <el-tag v-if="node.isMyTurn" type="danger" size="small" effect="dark">待我处理</el-tag>
                  <el-button
                    v-if="node.subNodes?.length"
                    type="primary"
                    size="small"
                    link
                    @click="toggleNodeExpand(node.nodeId)"
                  >
                    {{ isNodeExpanded(node.nodeId) ? '收起' : '展开' }} 子节点 ({{ node.subNodes.length }})
                  </el-button>
                </div>
                <!-- 任务分配信息 -->
                <div v-if="node.tasks?.length && !node.subNodes?.length" class="node-tasks">
                  <div
                    v-for="task in node.tasks"
                    :key="task.id"
                    class="task-item"
                  >
                    <span class="task-assignee">{{ task.assigneeName || '用户' + task.assigneeId }}</span>
                    <el-tag :type="taskStatusType(task.status)" size="small">
                      {{ taskStatusText(task.status) }}
                    </el-tag>
                    <span v-if="task.comment" class="task-comment">{{ task.comment }}</span>
                  </div>
                </div>
                <!-- 该节点的审批记录 -->
                <div v-if="getNodeRecords(node.nodeId).length && !node.subNodes?.length" class="node-records">
                  <div
                    v-for="record in getNodeRecords(node.nodeId)"
                    :key="record.id"
                    class="record-item"
                  >
                    <span class="record-operator">{{ record.operatorName || '用户' + record.operatorId }}</span>
                    <el-tag :type="recordActionType(record.actionResult)" size="small">
                      {{ recordActionText(record.actionResult) }}
                    </el-tag>
                    <span v-if="record.comment" class="record-comment">{{ record.comment }}</span>
                    <span class="record-time">{{ record.createTime }}</span>
                  </div>
                </div>
                <!-- 子节点列表 -->
                <div v-if="node.subNodes?.length && isNodeExpanded(node.nodeId)" class="sub-node-list">
                  <div
                    v-for="sub in node.subNodes"
                    :key="sub.subNodeId"
                    class="sub-node-item"
                    :class="{ 'current-sub-node': sub.status === 'current' }"
                    :ref="el => setSubNodeRef(node.nodeId, sub.subNodeId, el)"
                  >
                    <div class="sub-node-title">
                      <span class="sub-node-name">{{ sub.subNodeName }}</span>
                      <el-tag v-if="sub.isMyTurn" type="danger" size="small" effect="dark">待我处理</el-tag>
                    </div>
                    <div v-if="sub.tasks?.length" class="node-tasks">
                      <div
                        v-for="task in sub.tasks"
                        :key="task.id"
                        class="task-item"
                      >
                        <span class="task-assignee">{{ task.assigneeName || '用户' + task.assigneeId }}</span>
                        <el-tag :type="taskStatusType(task.status)" size="small">
                          {{ taskStatusText(task.status) }}
                        </el-tag>
                        <span v-if="task.comment" class="task-comment">{{ task.comment }}</span>
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </el-timeline-item>
          </el-timeline>
        </div>

        <!-- 右侧：审批操作区 -->
        <div class="action-section">
          <template v-if="myPendingTask">
            <h4>审批操作</h4>
            <el-form ref="formRef" :model="form" label-width="80px">
              <el-form-item label="操作">
                <el-radio-group v-model="form.action">
                  <el-radio label="pass">通过</el-radio>
                  <el-radio label="reject">拒绝</el-radio>
                  <el-radio label="rollback">回退</el-radio>
                </el-radio-group>
              </el-form-item>
              <el-form-item v-if="form.action === 'pass' && nextNodes.length > 0" label="选择分支">
                <el-select v-model="form.targetNodeId" placeholder="请选择下一节点" style="width: 100%">
                  <el-option v-for="n in nextNodes" :key="n.nodeId" :label="n.nodeName" :value="n.nodeId" />
                </el-select>
              </el-form-item>
              <el-form-item v-if="form.action === 'rollback'" label="回退说明">
                <el-alert type="warning" :closable="false" show-icon>
                  <template #title>
                    提交后将自动回退到上一个审批节点
                    <div v-if="lastRollbackRecord" class="rollback-reason">
                      上次回退原因：{{ lastRollbackRecord.comment }}
                    </div>
                  </template>
                </el-alert>
              </el-form-item>
              <!-- TODO: 接入OSS后重新启用附件功能 -->
              <el-form-item v-if="false" label="附件">
                <el-upload
                  v-model:file-list="fileUpload.attachmentList"
                  action="#"
                  :http-request="fileUpload.handleUpload"
                  :before-upload="beforeFileUpload"
                  :before-remove="() => true"
                  :limit="5"
                  multiple
                  :on-preview="fileUpload.handleFilePreview"
                >
                  <el-button type="primary" size="small">上传附件</el-button>
                </el-upload>
              </el-form-item>
              <el-form-item label="意见">
                <el-input v-model="form.comment" type="textarea" placeholder="请输入审批意见" />
              </el-form-item>
              <el-form-item>
                <el-button type="primary" :loading="submitting" @click="submitApprove">提交</el-button>
                <el-button :loading="submitting" @click="handleAddSign">加签</el-button>
              </el-form-item>
            </el-form>
          </template>
          <template v-else>
            <el-empty description="当前没有需要您处理的审批任务" />
          </template>

        </div>
      </div>
    </div>
  </el-drawer>

  <!-- 加签弹窗 -->
  <el-dialog
    v-model="addSignDialogVisible"
    title="加签"
    width="400px"
    :close-on-click-modal="false"
  >
    <el-select v-model="addSignUserId" filterable placeholder="请选择加签人" style="width: 100%">
      <el-option v-for="u in userList" :key="u.id" :label="u.realName || u.username" :value="u.id" />
    </el-select>
    <template #footer>
      <el-button @click="addSignDialogVisible = false">取消</el-button>
      <el-button type="primary" :loading="submitting" @click="confirmAddSign">确认</el-button>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { ref, reactive, computed, watch, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import { getProgress, getInstanceAttachments, updateInstanceFormData } from '@/api/flow/instance'
import { approveTask, rejectTask, returnTask, addSignTask, getTransferableUsers, listNextNodes } from '@/api/flow/task'
import type { NextNode } from '@/types/flow'
import { beforeFileUpload, getFileUrl, getFileName, parseAttachments, collectAttachmentUrls } from '@/utils/file'
import { useFileUpload } from '@/composables/useFileUpload'
import { instanceStatusText, instanceStatusTagType, taskStatusText, taskStatusType, recordActionText, recordActionType } from '@/utils/flow'
import FilePreview from '@/components/FilePreview/index.vue'
import FormDataDisplay from '@/components/FormDataDisplay/index.vue'
import FlowFormFields from '@/components/FlowFormFields/index.vue'
import type { ProcessProgress, FlowTask, ApprovalAction, Attachment } from '@/types/flow'
import type { User } from '@/types/system'
import { CircleCheck, Clock, Document } from '@element-plus/icons-vue'

const props = defineProps<{
  modelValue: boolean
  instanceId: number
}>()

const emit = defineEmits<{
  (e: 'update:modelValue', val: boolean): void
  (e: 'approved'): void
}>()

const visible = computed({
  get: () => props.modelValue,
  set: (val) => emit('update:modelValue', val)
})

const loading = ref(false)
const progress = ref<ProcessProgress | null>(null)
const expandedNodes = ref<Set<string>>(new Set())
const subNodeRefs = ref<Record<string, Record<string, HTMLElement | null>>>({})

type ApprovalActionType = 'pass' | 'reject' | 'rollback'

const form = reactive<{
  action: ApprovalActionType
  comment: string
  targetNodeId?: string
}>({
  action: 'pass',
  comment: '',
  targetNodeId: undefined
})

const fileUpload = reactive(useFileUpload())
const submitting = ref(false)
const addSignDialogVisible = ref(false)
const addSignUserId = ref<number | undefined>(undefined)
const userList = ref<User[]>([])

async function loadTransferableUsers() {
  const task = myPendingTask.value
  if (!task) {
    userList.value = []
    return
  }
  try {
    userList.value = await getTransferableUsers(task.id)
  } catch {
    userList.value = []
  }
}

// 是否有表单数据用于展示
const formDataDisplay = computed(() => {
  return !!progress.value?.instance?.formData
})

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

// 实例附件列表（从附件表读取，包含所有节点上传的历史附件）
const instanceAttachments = computed(() => {
  return attachments.value.map(a => a.fileUrl)
})

// 图片预览列表
const imagePreviewList = computed(() => {
  return attachments.value.filter(a => isImage(a.fileUrl)).map(a => getFileUrl(a.fileUrl))
})

async function loadAttachments() {
  if (!props.instanceId) return
  try {
    attachments.value = await getInstanceAttachments(props.instanceId)
  } catch {
    attachments.value = []
  }
}

function isImage(url: string): boolean {
  return /\.(png|jpe?g|gif|webp|bmp)$/i.test(url)
}

// 查找当前登录用户需要处理的待办任务
// 分支选择
const nextNodes = ref<NextNode[]>([])

async function loadNextNodes(taskId: number) {
  try { nextNodes.value = await listNextNodes(taskId) } catch { nextNodes.value = [] }
}

const myPendingTask = computed<FlowTask | null>(() => {
  if (!progress.value) return null
  for (const node of progress.value.nodes) {
    if (node.isMyTurn && node.tasks) {
      const pending = node.tasks.find(t => t.status === 0)
      if (pending) return pending
    }
    if (node.subNodes) {
      for (const sub of node.subNodes) {
        if (sub.isMyTurn && sub.tasks) {
          const pending = sub.tasks.find(t => t.status === 0)
          if (pending) {
            // 给子节点任务附加父节点名称，便于审批操作区展示
            pending.nodeName = `${node.nodeName} / ${sub.subNodeName}`
            return pending
          }
        }
      }
    }
  }
  return null
})

function timelineType(status: string) {
  if (status === 'completed') return 'success'
  if (status === 'current') return 'warning'
  return 'info'
}

function timelineIcon(status: string) {
  if (status === 'completed') return CircleCheck
  if (status === 'current') return Clock
  return undefined
}

function getNodeRecords(nodeId: string) {
  if (!progress.value?.records) return []
  return progress.value.records.filter(r => r.nodeId === nodeId)
}

function timelineColor(status: string) {
  if (status === 'completed') return '#67C23A'
  if (status === 'current') return '#E6A23C'
  return '#909399'
}

async function loadProgress() {
  if (!props.instanceId) return
  loading.value = true
  try {
    // 静默加载进度，无权限时不在详情页弹全局错误提示
    const res = await getProgress(props.instanceId, { silent: true })
    progress.value = res
    autoExpandSubNodes()
  } catch {
    progress.value = null
  } finally {
    loading.value = false
  }
}

function autoExpandSubNodes() {
  if (!progress.value?.nodes) return
  expandedNodes.value.clear()
  subNodeRefs.value = {}
  for (const node of progress.value.nodes) {
    if (!node.subNodes?.length) continue
    const hasCurrentSub = node.subNodes.some(s => s.status === 'current')
    if (node.status === 'current' || hasCurrentSub) {
      expandedNodes.value.add(node.nodeId)
    }
  }
  nextTick(() => scrollToCurrentSubNode())
}

function scrollToCurrentSubNode() {
  if (!progress.value?.nodes) return
  for (const node of progress.value.nodes) {
    if (!node.subNodes?.length || !isNodeExpanded(node.nodeId)) continue
    const currentSub = node.subNodes.find(s => s.status === 'current')
    if (currentSub) {
      const el = subNodeRefs.value[node.nodeId]?.[currentSub.subNodeId]
      el?.scrollIntoView({ behavior: 'smooth', block: 'center' })
      return
    }
  }
}

function setSubNodeRef(nodeId: string, subNodeId: string, el: any) {
  if (!subNodeRefs.value[nodeId]) {
    subNodeRefs.value[nodeId] = {}
  }
  subNodeRefs.value[nodeId][subNodeId] = el as HTMLElement | null
}

function toggleNodeExpand(nodeId: string) {
  if (expandedNodes.value.has(nodeId)) {
    expandedNodes.value.delete(nodeId)
  } else {
    expandedNodes.value.add(nodeId)
  }
}

function isNodeExpanded(nodeId: string): boolean {
  return expandedNodes.value.has(nodeId)
}

async function submitApprove() {
  const task = myPendingTask.value
  if (!task) return
  if (form.action === 'pass' && nextNodes.value.length > 0 && !form.targetNodeId) {
    ElMessage.warning('存在多个下游分支，请选择一个目标节点')
    return
  }
  submitting.value = true
  try {
    const data: ApprovalAction = {
      action: form.action,
      comment: form.comment
    }
    if (fileUpload.attachmentList.length > 0) {
      data.attachmentUrls = collectAttachmentUrls(fileUpload.attachmentList)
    }
    if (form.action === 'pass' && form.targetNodeId) {
      data.targetNodeId = form.targetNodeId
    }
    switch (form.action) {
      case 'pass':
        await approveTask(task.id, data)
        break
      case 'reject':
        await rejectTask(task.id, data)
        break
      case 'rollback':
        await returnTask(task.id, data)
        break
    }
    ElMessage.success('审批提交成功')
    form.action = 'pass'
    form.comment = ''
    fileUpload.resetFileUpload()
    // 刷新进度展示最新状态，不关闭抽屉
    await loadProgress()
    emit('approved')
  } finally {
    submitting.value = false
  }
}

function handleClose() {
  progress.value = null
  fileUpload.resetFileUpload()
  attachments.value = []
  cancelEditForm()
}

// 表单补充/编辑
const formEditing = ref(false)
const savingForm = ref(false)
const editFormData = ref<Record<string, unknown>>({})
const formFieldsRef = ref<{ validate: () => boolean } | null>(null)

const canEditForm = computed(() => !!myPendingTask.value)

function parseInstanceFormData(): Record<string, unknown> {
  const fd = progress.value?.instance?.formData
  if (!fd) return {}
  if (fd !== null && typeof fd === 'object') return { ...fd as Record<string, unknown> }
  try {
    return JSON.parse(fd as string)
  } catch {
    return {}
  }
}

function startEditForm() {
  editFormData.value = parseInstanceFormData()
  formEditing.value = true
}

function cancelEditForm() {
  formEditing.value = false
  editFormData.value = {}
}

async function saveFormData() {
  const valid = formFieldsRef.value?.validate?.()
  if (valid === false) return
  savingForm.value = true
  try {
    await updateInstanceFormData(props.instanceId, editFormData.value)
    ElMessage.success('材料已更新')
    cancelEditForm()
    await loadProgress()
    emit('approved')
  } finally {
    savingForm.value = false
  }
}

// 当前节点最近一次被回退的记录
const lastRollbackRecord = computed(() => {
  if (!progress.value?.records) return null
  const currentNodeId = progress.value.instance?.currentNode
  const list = progress.value.records.filter(r =>
    r.nodeId === currentNodeId && (r.actionType === 'RETURN' || r.actionResult === 'RETURN')
  )
  return list.length > 0 ? list[list.length - 1] : null
})

function handleAddSign() {
  const task = myPendingTask.value
  if (!task) return
  addSignUserId.value = undefined
  addSignDialogVisible.value = true
}

async function confirmAddSign() {
  const task = myPendingTask.value
  if (!task || !addSignUserId.value) {
    ElMessage.warning('请选择加签人')
    return
  }
  submitting.value = true
  try {
    await addSignTask(task.id, addSignUserId.value)
    ElMessage.success('加签成功')
    addSignDialogVisible.value = false
    addSignUserId.value = undefined
    await loadProgress()
  } finally {
    submitting.value = false
  }
}

watch(() => props.instanceId, (id) => {
  if (id && props.modelValue) {
    loadProgress()
  }
})

// 切换到"通过"或当前待办任务变化时加载下游节点列表
watch(
  [() => form.action, () => myPendingTask.value?.id],
  ([action, taskId]) => {
    nextNodes.value = []
    form.targetNodeId = undefined
    if (action === 'pass' && taskId) {
      loadNextNodes(taskId)
    }
  }
)

watch(() => props.modelValue, async (val) => {
  if (val && props.instanceId) {
    await loadProgress()
    await loadTransferableUsers()
    loadAttachments()
  }
})
</script>

<style scoped>
.detail-content {
  height: calc(100vh - 120px);
  overflow-y: auto;
  padding-right: 8px;
}
.info-section {
  margin-bottom: 10px;
}
.form-data-section,
.attachment-section {
  margin-bottom: 10px;
}
.form-data-section h4,
.attachment-section h4 {
  margin: 0 0 8px 0;
  font-size: 15px;
  color: #303133;
}
.attachment-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.attachment-item {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 8px 12px;
  background: #f5f7fa;
  border-radius: 4px;
}
.attachment-name {
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.attachment-meta {
  font-size: 12px;
  color: #909399;
}
.detail-body {
  display: flex;
  gap: 24px;
}
.timeline-section {
  flex: 1;
  min-width: 0;
}
.action-section {
  flex: 1;
  min-width: 0;
  border-left: 1px solid #ebeef5;
  padding-left: 24px;
}
.timeline-section h4,
.action-section h4 {
  margin: 0 0 16px 0;
  font-size: 15px;
  color: #303133;
}
.node-item {
  padding: 4px 0;
}
.node-item.current-node {
  background: #fdf6ec;
  padding: 8px;
  border-radius: 4px;
}
.node-title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}
.node-name {
  font-weight: bold;
  color: #303133;
}
.node-tasks {
  padding-left: 8px;
}
.task-item {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: #606266;
  margin: 4px 0;
}
.task-comment {
  color: #909399;
}
.record-list {
  max-height: 300px;
  overflow-y: auto;
}
.node-records {
  margin-top: 8px;
  padding-left: 12px;
  border-left: 2px solid #e4e7ed;
}
.record-item {
  padding: 6px 0;
}
.record-item:last-child {
  border-bottom: none;
}
.record-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 6px;
}
.record-operator {
  font-weight: bold;
  color: #303133;
}
.record-time {
  font-size: 12px;
  color: #909399;
}
.record-comment {
  font-size: 13px;
  color: #606266;
  background: #f5f7fa;
  padding: 6px 10px;
  border-radius: 4px;
  margin-bottom: 6px;
}
.record-attachments {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.section-title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}
.section-title h4 {
  margin: 0;
}
.form-edit-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 12px;
}
.rollback-reason {
  margin-top: 4px;
  font-size: 13px;
  color: #e6a23c;
  line-height: 1.5;
}
.sub-node-list {
  margin-top: 8px;
  padding-left: 12px;
  border-left: 2px solid #e4e7ed;
}
.sub-node-item {
  padding: 8px;
  margin: 8px 0;
  background: #f5f7fa;
  border-radius: 4px;
}
.sub-node-item.current-sub-node {
  background: #fdf6ec;
  border: 1px solid #f5dab1;
}
.sub-node-title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}
.sub-node-name {
  font-weight: bold;
  color: #303133;
  font-size: 13px;
}
</style>
