<template>
  <section class="approval-task-workspace">
    <p v-if="statusMessage" class="workspace-message success" aria-live="polite">
      <i class="mdi mdi-check-circle-outline"></i>
      {{ statusMessage }}
    </p>
    <p v-if="workspaceError" class="workspace-message error" role="alert">
      <i class="mdi mdi-alert-circle-outline"></i>
      {{ workspaceError }}
    </p>

    <ApprovalTaskQueue
      ref="queueRef"
      :initial-filters="initialFilters"
      :initial-page="initialPage"
      :initial-page-size="initialPageSize"
      :refresh-token="refreshToken"
      :service-overrides="serviceOverrides"
      @open-detail="openDetail"
      @action="openAction"
      @batch-result="handleBatchResult"
      @loaded="handleQueueLoaded"
      @state-change="$emit('state-change', $event)"
      @error="handleQueueError"
    />

    <ApprovalAssignmentDialog
      :open="assignmentOpen"
      :task="activeItem"
      :mode="actionMode"
      :service-overrides="serviceOverrides"
      @close="closeAction"
      @completed="handleMutationCompleted"
    />

    <ApprovalParticipantsDialog
      :open="participantsOpen"
      :task="activeItem"
      :mode="actionMode"
      :service-overrides="serviceOverrides"
      @close="closeAction"
      @completed="handleMutationCompleted"
    />

    <ConfirmDialog
      :open="decisionOpen"
      :badge="decisionMeta.badge"
      :badge-tone="decisionMeta.badgeTone"
      :title="decisionMeta.title"
      :description="decisionMeta.description"
      cancel-text="返回核对"
      :confirm-text="decisionMeta.confirmText"
      busy-text="提交中..."
      :confirm-tone="decisionMeta.confirmTone"
      :confirm-icon="decisionMeta.icon"
      :busy="actionBusy"
      :confirm-disabled="decisionReason.trim().length < 2"
      :close-on-mask="false"
      @close="closeAction"
      @confirm="submitDecision"
    >
      <p v-if="actionError" class="workspace-message error" role="alert">
        {{ actionError }}
      </p>
      <label class="workspace-reason">
        <span>{{ decisionMeta.reasonLabel }} <em>必填</em></span>
        <textarea
          v-model="decisionReason"
          maxlength="500"
          :disabled="actionBusy"
          :placeholder="decisionMeta.placeholder"
        ></textarea>
        <small>{{ decisionReason.trim().length }}/500</small>
      </label>
    </ConfirmDialog>

    <ReturnReasonDialog
      :open="returnOpen"
      :busy="actionBusy"
      :claim-no="activeClaimNo"
      :application="activeIsApplication"
      :error="actionError"
      @close="closeAction"
      @confirm="submitReturn"
    />
  </section>
</template>

<script setup>
import { computed, onMounted, ref, watch } from 'vue'

import {
  approveApprovalTask,
  escalateApprovalTask,
  fetchApprovalTasks,
  returnApprovalTask
} from '../../services/approvalTasks.js'
import { isApplicationDocumentNo } from '../../utils/documentClassification.js'
import { resolveApprovalTaskRetryKey } from '../../views/scripts/approvalTaskRetry.js'
import ConfirmDialog from '../shared/ConfirmDialog.vue'
import ReturnReasonDialog from '../shared/ReturnReasonDialog.vue'
import ApprovalAssignmentDialog from './ApprovalAssignmentDialog.vue'
import ApprovalParticipantsDialog from './ApprovalParticipantsDialog.vue'
import ApprovalTaskQueue from './ApprovalTaskQueue.vue'

const DECISION_META = {
  approve: {
    badge: '审批通过',
    badgeTone: 'info',
    title: '确认通过当前审批任务吗？',
    description: '提交时会重新校验任务版本、审批权限、开放风险和单据状态。',
    confirmText: '确认通过',
    confirmTone: 'primary',
    icon: 'mdi mdi-check-circle-outline',
    reasonLabel: '审批意见',
    placeholder: '写明核对结论，至少 2 个字。'
  },
  sla_escalate: {
    badge: '任务升级',
    badgeTone: 'warning',
    title: '确认立即升级该审批任务吗？',
    description: '升级只改变任务优先级和 SLA 审计信息，不会替代审批人的最终决定。',
    confirmText: '确认升级',
    confirmTone: 'warning',
    icon: 'mdi mdi-arrow-up-bold-circle-outline',
    reasonLabel: '升级原因',
    placeholder: '说明需要立即升级的业务原因。'
  }
}
const ASSIGNMENT_ACTIONS = new Set(['delegate', 'transfer', 'delegation_revoke'])
const PARTICIPANT_ACTIONS = new Set(['add_sign', 'countersign'])

const props = defineProps({
  initialFilters: { type: Object, default: () => ({}) },
  initialPage: { type: Number, default: 1 },
  initialPageSize: { type: Number, default: 20 },
  refreshToken: { type: [String, Number], default: 0 },
  serviceOverrides: { type: Object, default: () => ({}) }
})
const emit = defineEmits(['open-document', 'request-updated', 'loaded', 'batch-result', 'state-change'])

const queueRef = ref(null)
const activeItem = ref(null)
const actionMode = ref('')
const decisionReason = ref('')
const actionBusy = ref(false)
const actionError = ref('')
const queueError = ref('')
const summaryError = ref('')
const statusMessage = ref('')
const requestId = ref('')
const requestFingerprint = ref('')

const activeTask = computed(() => activeItem.value?.task || activeItem.value || {})
const activeClaim = computed(() => activeItem.value?.claim || {})
const activeTaskId = computed(() => String(activeTask.value.id || '').trim())
const activeClaimNo = computed(() => String(
  activeClaim.value.claim_no || activeClaim.value.claimNo || activeTask.value.claimId || ''
).trim())
const activeIsApplication = computed(() => (
  isApplicationDocumentNo(activeClaimNo.value)
  || ['application', 'expense_application'].includes(String(
    activeClaim.value.expense_type || activeClaim.value.expenseType || ''
  ).trim())
))
const assignmentOpen = computed(() => ASSIGNMENT_ACTIONS.has(actionMode.value))
const participantsOpen = computed(() => PARTICIPANT_ACTIONS.has(actionMode.value))
const decisionOpen = computed(() => ['approve', 'sla_escalate'].includes(actionMode.value))
const returnOpen = computed(() => actionMode.value === 'return')
const decisionMeta = computed(() => DECISION_META[actionMode.value] || DECISION_META.approve)
const workspaceError = computed(() => queueError.value || summaryError.value)
let summaryRequestSequence = 0

onMounted(() => void loadTaskSummary())
watch(() => props.refreshToken, () => void loadTaskSummary())

function openDetail(item) {
  const task = item?.task || item || {}
  const claim = item?.claim || {}
  const claimId = String(task.claimId || task.claim_id || item?.claimId || '').trim()
  emit('open-document', {
    claimId,
    id: claimId,
    claimNo: String(claim.claim_no || claim.claimNo || '').trim(),
    detailLookupOnly: true
  })
}

function openAction(payload = {}) {
  const action = String(payload.action || '').trim()
  if (![...ASSIGNMENT_ACTIONS, ...PARTICIPANT_ACTIONS, 'approve', 'return', 'sla_escalate'].includes(action)) {
    return
  }
  activeItem.value = payload.item || null
  actionMode.value = action
  decisionReason.value = ''
  actionError.value = ''
  statusMessage.value = ''
  requestId.value = ''
  requestFingerprint.value = ''
}

function closeAction() {
  if (actionBusy.value) return
  activeItem.value = null
  actionMode.value = ''
  decisionReason.value = ''
  actionError.value = ''
  requestId.value = ''
  requestFingerprint.value = ''
}

async function submitDecision() {
  if (actionBusy.value || decisionReason.value.trim().length < 2) return
  const service = actionMode.value === 'approve'
    ? props.serviceOverrides.approveApprovalTask || approveApprovalTask
    : props.serviceOverrides.escalateApprovalTask || escalateApprovalTask
  const payload = {
    expectedTaskVersion: Number(activeTask.value.version),
    reason: decisionReason.value.trim()
  }
  if (actionMode.value === 'approve') payload.opinion = decisionReason.value.trim()
  attachRetryRequestId(payload)
  await executeAction(() => service(activeTaskId.value, payload))
}

async function submitReturn(payload = {}) {
  if (actionBusy.value) return
  const service = props.serviceOverrides.returnApprovalTask || returnApprovalTask
  const actionPayload = {
    expectedTaskVersion: Number(activeTask.value.version),
    reason: String(payload.reason || '').trim(),
    reasonCodes: Array.isArray(payload.reason_codes) ? payload.reason_codes : []
  }
  attachRetryRequestId(actionPayload)
  await executeAction(() => service(activeTaskId.value, actionPayload))
}

function attachRetryRequestId(payload) {
  const retryKey = resolveApprovalTaskRetryKey({
    action: actionMode.value,
    scopeId: activeTaskId.value || 'task',
    payload,
    previousFingerprint: requestFingerprint.value,
    previousRequestId: requestId.value
  })
  requestId.value = retryKey.requestId
  requestFingerprint.value = retryKey.fingerprint
  payload.requestId = retryKey.requestId
}

async function executeAction(executor) {
  actionBusy.value = true
  actionError.value = ''
  try {
    const mutation = await executor()
    await finishMutation(actionMode.value, mutation)
  } catch (error) {
    actionError.value = error?.message || '审批任务操作失败，请按当前 request_id 安全重试。'
  } finally {
    actionBusy.value = false
  }
}

async function handleMutationCompleted(payload = {}) {
  await finishMutation(payload.mode || actionMode.value, payload.mutation)
}

async function finishMutation(mode, mutation) {
  const labels = {
    approve: '审批通过',
    return: '退回',
    delegate: '委托',
    delegation_revoke: '撤销委托',
    transfer: '转交',
    add_sign: '加签',
    countersign: '会签',
    sla_escalate: '任务升级'
  }
  statusMessage.value = mutation?.replayed
    ? `${labels[mode] || '任务操作'}结果已安全重放。`
    : `${labels[mode] || '任务操作'}已完成。`
  if (mutation?.claim) emit('request-updated', { claim: mutation.claim })
  activeItem.value = null
  actionMode.value = ''
  decisionReason.value = ''
  requestId.value = ''
  requestFingerprint.value = ''
  try {
    await queueRef.value?.reload?.()
  } catch {
    queueError.value = '操作已成功，但任务列表刷新失败，请稍后手动刷新。'
  }
  await loadTaskSummary()
}

function handleBatchResult(result) {
  statusMessage.value = result?.status === 'succeeded'
    ? `批量审批完成：成功 ${Number(result.succeededCount || 0) + Number(result.replayedCount || 0)} 项。`
    : '批量审批已完成，部分任务需要单独处理。'
  const completedItems = (Array.isArray(result?.items) ? result.items : [])
    .filter((item) => ['succeeded', 'replayed'].includes(String(item?.status || '').toLowerCase()))
  const claims = completedItems.map((item) => item?.claim).filter(Boolean)
  const claimIds = completedItems.map((item) => item?.claimId).filter(Boolean)
  if (completedItems.length) {
    emit('request-updated', { claim: claims[0], claimId: claimIds[0], claimIds })
  }
  void loadTaskSummary()
  emit('batch-result', result)
}

function handleQueueError(error) {
  queueError.value = error?.message || '审批任务队列加载失败。'
}

function handleQueueLoaded() {
  queueError.value = ''
}

async function loadTaskSummary() {
  const sequence = ++summaryRequestSequence
  try {
    const service = props.serviceOverrides.fetchApprovalTasks || fetchApprovalTasks
    const result = await service({ status: 'pending', page: 1, pageSize: 1 })
    if (sequence !== summaryRequestSequence) return
    summaryError.value = ''
    emit('loaded', result)
  } catch (error) {
    if (sequence === summaryRequestSequence) {
      summaryError.value = error?.message || '审批任务总数同步失败。'
    }
  }
}
</script>

<style scoped>
.approval-task-workspace {
  display: grid;
  gap: 10px;
  min-width: 0;
}

.workspace-message {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  padding: 9px 11px;
  border: 1px solid;
  border-radius: 7px;
  font-size: 12px;
  font-weight: 750;
}

.workspace-message.success {
  border-color: #a7f3d0;
  background: #ecfdf5;
  color: #047857;
}

.workspace-message.error {
  border-color: #fecaca;
  background: #fef2f2;
  color: #b91c1c;
}

.workspace-reason {
  display: grid;
  gap: 7px;
}

.workspace-reason span,
.workspace-reason small {
  color: #475569;
  font-size: 12px;
}

.workspace-reason em {
  color: #b91c1c;
  font-style: normal;
}

.workspace-reason textarea {
  min-height: 90px;
  padding: 10px;
  border: 1px solid #dbe5ef;
  border-radius: 6px;
  resize: vertical;
}
</style>
