import { computed, reactive, ref } from 'vue'

import { fetchExpenseClaims } from '../services/reimbursements.js'
import { filterActionableRiskFlags } from '../utils/riskFlags.js'

const EXPENSE_TYPE_LABELS = {
  travel: '差旅费',
  travel_application: '差旅费用申请',
  expense_application: '费用申请',
  purchase_application: '采购费用申请',
  meeting_application: '会务费用申请',
  train_ticket: '火车票',
  flight_ticket: '机票',
  ship_ticket: '轮船票',
  ferry_ticket: '轮船票',
  hotel_ticket: '住宿票',
  ride_ticket: '乘车',
  travel_allowance: '出差补贴',
  entertainment: '业务招待费',
  marketing: '市场推广费',
  office: '办公用品费',
  meeting: '会务费',
  training: '培训费',
  software: '软件服务费',
  hotel: '住宿费',
  transport: '交通费',
  meal: '业务招待费',
  other: '其他费用'
}

const LOCATION_REQUIRED_EXPENSE_TYPES = new Set([
  'travel',
  'train_ticket',
  'flight_ticket',
  'hotel_ticket',
  'ride_ticket',
  'meeting',
  'entertainment'
])

const SYSTEM_GENERATED_EXPENSE_TYPES = new Set(['travel_allowance'])
const LONG_DISTANCE_TRAVEL_EXPENSE_TYPES = new Set(['train_ticket', 'flight_ticket'])
const ROUTE_DESCRIPTION_EXPENSE_TYPES = new Set(['train_ticket', 'flight_ticket', 'ship_ticket', 'ferry_ticket', 'ride_ticket'])
const HOTEL_DESCRIPTION_EXPENSE_TYPES = new Set(['hotel_ticket'])
const DOCUMENT_TYPE_APPLICATION = 'application'
const DOCUMENT_TYPE_REIMBURSEMENT = 'reimbursement'

const REIMBURSEMENT_PROGRESS_LABELS = [
  '创建单据',
  '待提交',
  'AI预审',
  '直属领导审批',
  '财务审批',
  '待付款',
  '已付款'
]

const APPLICATION_PROGRESS_LABELS = [
  '创建申请',
  '直属领导审批',
  '预算管理者审批',
  '审批完成'
]

function parseNumber(value) {
  const nextValue = Number(value)
  return Number.isFinite(nextValue) ? nextValue : 0
}

function toDate(value) {
  if (!value) {
    return null
  }

  const nextDate = new Date(value)
  return Number.isNaN(nextDate.getTime()) ? null : nextDate
}

function formatDate(value) {
  const nextDate = toDate(value)
  if (!nextDate) {
    return ''
  }

  const year = nextDate.getFullYear()
  const month = String(nextDate.getMonth() + 1).padStart(2, '0')
  const day = String(nextDate.getDate()).padStart(2, '0')
  return `${year}-${month}-${day}`
}

function formatDateTime(value) {
  const nextDate = toDate(value)
  if (!nextDate) {
    return ''
  }

  const hours = String(nextDate.getHours()).padStart(2, '0')
  const minutes = String(nextDate.getMinutes()).padStart(2, '0')
  return `${formatDate(nextDate)} ${hours}:${minutes}`
}

function formatDurationFrom(value, now = Date.now()) {
  const startAt = toDate(value)
  if (!startAt) {
    return ''
  }

  const diffMs = Math.max(0, Number(now) - startAt.getTime())
  const totalMinutes = Math.floor(diffMs / (60 * 1000))
  if (totalMinutes < 1) {
    return '刚刚'
  }

  const days = Math.floor(totalMinutes / (24 * 60))
  const hours = Math.floor((totalMinutes % (24 * 60)) / 60)
  const minutes = totalMinutes % 60

  if (days > 0) {
    return hours > 0 ? `${days}天${hours}小时` : `${days}天`
  }

  if (hours > 0) {
    return minutes > 0 ? `${hours}小时${minutes}分钟` : `${hours}小时`
  }

  return `${minutes}分钟`
}

function formatAmount(value) {
  return new Intl.NumberFormat('zh-CN', {
    style: 'currency',
    currency: 'CNY',
    minimumFractionDigits: 0,
    maximumFractionDigits: Number.isInteger(value) ? 0 : 2
  }).format(parseNumber(value))
}

function resolveTypeLabel(typeCode) {
  return EXPENSE_TYPE_LABELS[String(typeCode || '').trim()] || EXPENSE_TYPE_LABELS.other
}

function resolveDocumentTypeMeta(claim, typeCode) {
  const explicitType = String(
    claim?.document_type_code
    || claim?.documentTypeCode
    || claim?.document_type
    || claim?.documentType
    || ''
  ).trim()
  const claimNo = String(claim?.claim_no || claim?.claimNo || '').trim().toUpperCase()
  const normalizedType = String(typeCode || '').trim()
  const isApplication =
    explicitType === DOCUMENT_TYPE_APPLICATION
    || explicitType === 'expense_application'
    || claimNo.startsWith('AP-')
    || claimNo.startsWith('APP-')
    || normalizedType === 'application'
    || normalizedType.endsWith('_application')

  return isApplication
    ? { documentTypeCode: DOCUMENT_TYPE_APPLICATION, documentTypeLabel: '申请单' }
    : { documentTypeCode: DOCUMENT_TYPE_REIMBURSEMENT, documentTypeLabel: '报销单' }
}

function normalizeExpenseType(typeCode) {
  return String(typeCode || '').trim() || 'other'
}

function isLocationRequiredExpenseType(typeCode) {
  return LOCATION_REQUIRED_EXPENSE_TYPES.has(normalizeExpenseType(typeCode))
}

function resolveLocationDisplay(location, typeCode) {
  const normalized = String(location || '').trim()
  if (normalized) {
    return normalized
  }

  return isLocationRequiredExpenseType(typeCode) ? '待补充' : '非必填'
}

function resolveExpenseDescriptionDetail(itemType, itemLocation) {
  const normalizedType = normalizeExpenseType(itemType)
  if (ROUTE_DESCRIPTION_EXPENSE_TYPES.has(normalizedType)) {
    return '起始地-目的地'
  }
  if (HOTEL_DESCRIPTION_EXPENSE_TYPES.has(normalizedType)) {
    return '目的地酒店'
  }
  return resolveLocationDisplay(itemLocation, normalizedType)
}

function resolveExpenseItemViewId(item, index, claim) {
  return String(item?.id || `${claim?.id || 'claim'}-item-${index}`)
}

function buildTravelTimeLabelMap(items, claim) {
  const travelItems = items
    .map((item, index) => {
      const itemType = normalizeExpenseType(item?.item_type || claim?.expense_type)
      return {
        id: resolveExpenseItemViewId(item, index, claim),
        index,
        itemType,
        itemDate: formatDate(item?.item_date),
        isSystemGenerated: Boolean(item?.is_system_generated || SYSTEM_GENERATED_EXPENSE_TYPES.has(itemType))
      }
    })
    .filter((item) => !item.isSystemGenerated && LONG_DISTANCE_TRAVEL_EXPENSE_TYPES.has(item.itemType))
    .sort((left, right) => {
      const dateCompare = String(left.itemDate || '').localeCompare(String(right.itemDate || ''))
      return dateCompare || left.index - right.index
    })

  const labels = new Map()
  travelItems.forEach((item, index) => {
    if (index === 0) {
      labels.set(item.id, '出发时间')
    } else if (index === travelItems.length - 1) {
      labels.set(item.id, '返回时间')
    } else {
      labels.set(item.id, '中转时间')
    }
  })
  return labels
}

function resolveExpenseTimeLabel({ id, itemType, isSystemGenerated, claim, travelTimeLabelMap }) {
  if (isSystemGenerated) {
    return '系统自动计算'
  }
  if (travelTimeLabelMap?.has(id)) {
    return travelTimeLabelMap.get(id)
  }
  if (itemType === 'ride_ticket') {
    return '乘车时间'
  }
  if (itemType === 'hotel_ticket') {
    return '住宿时间'
  }
  return claim?.expense_type === 'travel' ? '出行时间' : '业务发生时间'
}

function resolveAttachmentDisplayName(value) {
  const normalized = String(value || '').trim()
  if (!normalized) {
    return ''
  }

  return normalized.split('/').filter(Boolean).pop() || normalized
}

function resolveApprovalMeta(status) {
  const normalized = String(status || '').trim().toLowerCase()

  if (normalized === 'draft') {
    return { key: 'draft', label: '草稿', tone: 'draft' }
  }

  if (normalized === 'returned') {
    return { key: 'supplement', label: '待提交', tone: 'warning' }
  }

  if (normalized === 'supplement') {
    return { key: 'supplement', label: '待补充', tone: 'warning' }
  }

  if (normalized === 'pending_payment') {
    return { key: 'pending_payment', label: '待付款', tone: 'warning' }
  }

  if (normalized === 'paid') {
    return { key: 'completed', label: '已付款', tone: 'success' }
  }

  if (['approved', 'completed', 'paid'].includes(normalized)) {
    return { key: 'completed', label: '已完成', tone: 'success' }
  }

  if (['rejected', 'cancelled'].includes(normalized)) {
    return { key: 'rejected', label: '已退回', tone: 'danger' }
  }

  return { key: 'in_progress', label: '审批中', tone: 'info' }
}

function resolveWorkflowNode(claim, approvalMeta, isApplicationDocument = false) {
  if (String(claim?.status || '').trim().toLowerCase() === 'returned') {
    return '待提交'
  }

  const rawNode = String(claim?.approval_stage || '').trim()

  if (rawNode) {
    if (rawNode === '审批流转') {
      return 'AI预审'
    }
    if (rawNode === '待补充') {
      return approvalMeta.key === 'draft' ? '待提交' : 'AI预审'
    }
    return rawNode
  }

  if (approvalMeta.key === 'draft' || approvalMeta.key === 'supplement' || approvalMeta.key === 'rejected') {
    return '待提交'
  }

  if (approvalMeta.key === 'pending_payment') {
    return '待付款'
  }

  if (approvalMeta.key === 'completed') {
    const normalizedStatus = String(claim?.status || '').trim().toLowerCase()
    return isApplicationDocument ? '审批完成' : normalizedStatus === 'paid' ? '已付款' : '归档入账'
  }

  return isApplicationDocument ? '直属领导审批' : 'AI预审'
}

function stringifyRiskFlag(value) {
  if (typeof value === 'string') {
    return value.trim()
  }

  if (!value || typeof value !== 'object') {
    return ''
  }

  for (const key of ['message', 'label', 'reason', 'name']) {
    const nextValue = String(value[key] || '').trim()
    if (nextValue) {
      return nextValue
    }
  }

  return ''
}

function buildRiskSummary(riskFlags) {
  if (!Array.isArray(riskFlags) || !riskFlags.length) {
    return '无'
  }

  const items = filterActionableRiskFlags(riskFlags).map((item) => stringifyRiskFlag(item)).filter(Boolean)
  return items.length ? items.join('；') : '无'
}

function buildOccurredDisplay(claim) {
  const itemDates = Array.isArray(claim?.items)
    ? claim.items.map((item) => formatDate(item?.item_date)).filter(Boolean)
    : []

  if (!itemDates.length) {
    return formatDate(claim?.occurred_at) || '待补充'
  }

  const sortedDates = [...new Set(itemDates)].sort()
  if (sortedDates.length === 1) {
    return sortedDates[0]
  }

  return `${sortedDates[0]} ~ ${sortedDates[sortedDates.length - 1]}`
}

function resolveProgressCurrentIndex(approvalMeta, workflowNode) {
  const normalizedNode = String(workflowNode || '').trim()

  if (approvalMeta.key === 'completed') {
    return 6
  }

  if (approvalMeta.key === 'pending_payment') {
    return 5
  }

  if (normalizedNode.includes('已付款')) {
    return 6
  }
  if (normalizedNode.includes('待付款')) {
    return 5
  }
  if (normalizedNode.includes('归档') || normalizedNode.includes('入账')) {
    return 6
  }
  if (normalizedNode.includes('财务')) {
    return 4
  }
  if (
    normalizedNode.includes('直属领导')
    || normalizedNode.includes('领导审批')
    || normalizedNode.includes('部门负责人')
    || normalizedNode.includes('负责人审批')
  ) {
    return 3
  }
  if (normalizedNode.includes('AI预审') || normalizedNode.includes('AI验审') || normalizedNode.includes('审批流转')) {
    return 2
  }
  if (normalizedNode.includes('待提交')) {
    return 1
  }

  if (approvalMeta.key === 'draft' || approvalMeta.key === 'supplement' || approvalMeta.key === 'rejected') {
    return 1
  }

  return 2
}

function resolveApplicationProgressCurrentIndex(approvalMeta, workflowNode) {
  const normalizedNode = String(workflowNode || '').trim()

  if (approvalMeta.key === 'completed') {
    return 3
  }

  if (normalizedNode.includes('审批完成') || normalizedNode.includes('申请完成')) {
    return 3
  }
  if (normalizedNode.includes('预算')) {
    return 2
  }
  if (
    normalizedNode.includes('直属领导')
    || normalizedNode.includes('领导审批')
    || normalizedNode.includes('部门负责人')
    || normalizedNode.includes('负责人审批')
  ) {
    return 1
  }
  if (approvalMeta.key === 'draft' || approvalMeta.key === 'supplement' || approvalMeta.key === 'rejected') {
    return 0
  }

  return 1
}

function normalizeText(value) {
  return String(value || '').trim()
}

function isEmailLike(value) {
  return /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(normalizeText(value))
}

function resolveDisplayName(...values) {
  for (const value of values) {
    const normalized = normalizeText(value)
    if (normalized && !isEmailLike(normalized)) {
      return normalized
    }
  }

  return ''
}

function resolveApplicationApproverName(claim) {
  return resolveDisplayName(
    claim?.manager_name,
    claim?.managerName,
    claim?.profile_manager,
    claim?.profileManager,
    claim?.direct_manager_name,
    claim?.directManagerName
  ) || '直属领导'
}

function resolveApplicationBudgetApproverName(claim) {
  const routeEvent = findApprovalEventForStep(claim, '直属领导审批')
  return resolveDisplayName(
    routeEvent?.next_approver_name,
    routeEvent?.nextApproverName,
    routeEvent?.budget_approver_name,
    routeEvent?.budgetApproverName
  ) || 'P8预算监控者'
}

function resolveProgressDisplayLabel(label, documentTypeCode, claim, approvalMeta) {
  const normalizedLabel = normalizeText(label)
  const workflowNode = normalizeText(claim?.approval_stage || claim?.workflowNode)
  if (
    documentTypeCode === DOCUMENT_TYPE_APPLICATION
    && approvalMeta.key !== 'completed'
    && normalizedLabel === '直属领导审批'
    && (
      workflowNode.includes('直属领导')
      || workflowNode.includes('领导审批')
      || workflowNode.includes('部门负责人')
      || workflowNode.includes('负责人审批')
    )
  ) {
    return `等待 ${resolveApplicationApproverName(claim)} 批复`
  }

  if (
    documentTypeCode === DOCUMENT_TYPE_APPLICATION
    && approvalMeta.key !== 'completed'
    && normalizedLabel === '预算管理者审批'
    && workflowNode.includes('预算')
  ) {
    return `等待 ${resolveApplicationBudgetApproverName(claim)} 批复`
  }

  return label
}

function getRiskFlags(claim) {
  return Array.isArray(claim?.risk_flags_json) ? claim.risk_flags_json : []
}

function getLatestEvent(events) {
  const sortedEvents = events
    .filter((item) => item && typeof item === 'object')
    .map((item) => ({ ...item, eventDate: toDate(item.created_at || item.createdAt) }))
    .filter((item) => item.eventDate)
    .sort((a, b) => a.eventDate.getTime() - b.eventDate.getTime())

  return sortedEvents.length ? sortedEvents[sortedEvents.length - 1] : null
}

function findApprovalEventForStep(claim, label) {
  const stepLabel = normalizeText(label)
  const events = getRiskFlags(claim).filter((flag) => {
    if (!flag || typeof flag !== 'object') {
      return false
    }

    const source = normalizeText(flag.source)
    if (!['manual_approval', 'budget_approval', 'finance_approval'].includes(source)) {
      return false
    }

    const previousStage = normalizeText(flag.previous_approval_stage || flag.previousApprovalStage)
    const nextStage = normalizeText(flag.next_approval_stage || flag.nextApprovalStage)

    if (stepLabel === '直属领导审批') {
      return (
        previousStage.includes('直属领导')
        || previousStage.includes('领导审批')
        || nextStage.includes('预算')
        || nextStage.includes('财务')
      )
    }

    if (stepLabel === '预算管理者审批') {
      return (
        source === 'budget_approval'
        || previousStage.includes('预算')
        || nextStage.includes('审批完成')
      )
    }

    if (stepLabel === '财务审批') {
      return (
        previousStage.includes('财务')
        || nextStage.includes('待付款')
        || nextStage.includes('归档')
        || nextStage.includes('入账')
        || nextStage.includes('完成')
      )
    }

    return false
  })

  return getLatestEvent(events)
}

function findLatestReturnEvent(claim) {
  return getLatestEvent(
    getRiskFlags(claim).filter((flag) => (
      flag
      && typeof flag === 'object'
      && normalizeText(flag.source) === 'manual_return'
    ))
  )
}

function findLatestPaymentEvent(claim) {
  return getLatestEvent(
    getRiskFlags(claim).filter((flag) => (
      flag
      && typeof flag === 'object'
      && (
        normalizeText(flag.source) === 'payment'
        || normalizeText(flag.event_type || flag.eventType) === 'expense_claim_payment_completed'
      )
    ))
  )
}

function findLatestApplicationReturnEvent(claim) {
  return getLatestEvent(
    getRiskFlags(claim).filter((flag) => {
      if (!flag || typeof flag !== 'object' || normalizeText(flag.source) !== 'manual_return') {
        return false
      }
      const eventType = normalizeText(flag.event_type || flag.eventType)
      const returnStage = normalizeText(flag.return_stage || flag.returnStage || flag.previous_approval_stage)
      const stageKey = normalizeText(flag.return_stage_key || flag.returnStageKey)
      return (
        eventType === 'expense_application_return'
        || stageKey === 'direct_manager'
        || returnStage.includes('直属领导')
        || returnStage.includes('领导审批')
      )
    })
  )
}

function buildProgressStepMeta(time, detail = '', title = '') {
  return {
    time,
    detail,
    title: title || [time, detail].filter(Boolean).join(' ')
  }
}

function buildCompletedStepMeta(claim, label) {
  const stepLabel = normalizeText(label)
  const employeeName = normalizeText(claim?.employee_name) || '申请人'

  if (stepLabel === '创建单据' || stepLabel === '创建申请') {
    const createdAt = formatDateTime(claim?.created_at)
    return buildProgressStepMeta(stepLabel === '创建申请' ? `${employeeName}发起申请` : `${employeeName}创建`, createdAt)
  }

  if (stepLabel === '待提交') {
    const submittedAt = formatDateTime(claim?.submitted_at)
    return buildProgressStepMeta(`${employeeName}提交`, submittedAt)
  }

  if (stepLabel === 'AI预审') {
    const reviewedAt = formatDateTime(claim?.submitted_at || claim?.updated_at)
    return buildProgressStepMeta('AI预审通过', reviewedAt)
  }

  if (stepLabel === '直属领导审批' || stepLabel === '预算管理者审批' || stepLabel === '财务审批') {
    const approvalEvent = findApprovalEventForStep(claim, stepLabel)
    if (approvalEvent) {
      const operator = resolveDisplayName(
        approvalEvent.operator,
        approvalEvent.operator_name,
        approvalEvent.operatorName,
        stepLabel === '直属领导审批' ? claim?.manager_name : '',
        stepLabel === '预算管理者审批' ? approvalEvent.next_approver_name : ''
      ) || (stepLabel === '财务审批' ? '财务' : stepLabel === '预算管理者审批' ? '预算监控者' : '直属领导')
      const approvedAt = formatDateTime(approvalEvent.created_at || approvalEvent.createdAt)
      return buildProgressStepMeta(`${operator}通过`, approvedAt, `${operator}审批通过 ${approvedAt}`.trim())
    }

    if (stepLabel === '财务审批') {
      const updatedAt = formatDateTime(claim?.updated_at)
      return buildProgressStepMeta('财务通过', updatedAt, `财务审批通过 ${updatedAt}`.trim())
    }

    if (stepLabel === '直属领导审批') {
      const returnEvent = findLatestApplicationReturnEvent(claim)
      if (returnEvent) {
        const handledAt = formatDateTime(returnEvent.created_at || returnEvent.createdAt)
        return buildProgressStepMeta('已处理', handledAt, `直属领导已处理 ${handledAt}`.trim())
      }
    }
  }

  if (stepLabel === '退回') {
    const returnEvent = findLatestApplicationReturnEvent(claim) || findLatestReturnEvent(claim)
    if (returnEvent) {
      const operator = resolveDisplayName(
        returnEvent.operator,
        returnEvent.operator_name,
        returnEvent.operatorName,
        claim?.manager_name
      ) || '直属领导'
      const returnedAt = formatDateTime(returnEvent.created_at || returnEvent.createdAt)
      return buildProgressStepMeta(`${operator}退回`, returnedAt, `${operator}退回 ${returnedAt}`.trim())
    }
  }

  if (stepLabel === '待付款') {
    const approvalEvent = findApprovalEventForStep(claim, '财务审批')
    const pendingAt = formatDateTime(approvalEvent?.created_at || approvalEvent?.createdAt || claim?.updated_at)
    return buildProgressStepMeta('待付款', pendingAt)
  }

  if (stepLabel === '已付款') {
    const paymentEvent = findLatestPaymentEvent(claim)
    const paidAt = formatDateTime(paymentEvent?.created_at || paymentEvent?.createdAt || claim?.updated_at)
    return buildProgressStepMeta('已付款', paidAt)
  }

  if (stepLabel === '归档入账') {
    const archivedAt = formatDateTime(claim?.updated_at)
    return buildProgressStepMeta('归档入账', archivedAt)
  }

  if (stepLabel === '审批完成') {
    const completedAt = formatDateTime(claim?.updated_at)
    return buildProgressStepMeta('审批完成', completedAt)
  }

  return buildProgressStepMeta('已完成')
}

function resolveCurrentStepStartedAt(claim, label) {
  const stepLabel = normalizeText(label)
  if (stepLabel === '创建单据' || stepLabel === '创建申请') {
    return claim?.created_at
  }
  if (stepLabel === '待提交') {
    const returnEvent = findLatestReturnEvent(claim)
    return returnEvent?.created_at || returnEvent?.createdAt || claim?.updated_at || claim?.created_at
  }
  if (stepLabel === 'AI预审') {
    return claim?.updated_at || claim?.submitted_at || claim?.created_at
  }
  if (stepLabel === '直属领导审批') {
    return claim?.submitted_at || claim?.updated_at || claim?.created_at
  }
  if (stepLabel === '预算管理者审批') {
    const leaderApprovalEvent = findApprovalEventForStep(claim, '直属领导审批')
    return leaderApprovalEvent?.created_at || leaderApprovalEvent?.createdAt || claim?.updated_at || claim?.submitted_at
  }
  if (stepLabel === '财务审批') {
    const leaderApprovalEvent = findApprovalEventForStep(claim, '直属领导审批')
    return leaderApprovalEvent?.created_at || leaderApprovalEvent?.createdAt || claim?.updated_at || claim?.submitted_at
  }
  if (stepLabel === '待付款') {
    const approvalEvent = findApprovalEventForStep(claim, '财务审批')
    return approvalEvent?.created_at || approvalEvent?.createdAt || claim?.updated_at || claim?.submitted_at
  }
  if (stepLabel === '已付款') {
    const paymentEvent = findLatestPaymentEvent(claim)
    return paymentEvent?.created_at || paymentEvent?.createdAt || claim?.updated_at || claim?.submitted_at
  }
  if (stepLabel === '归档入账' || stepLabel === '审批完成') {
    return claim?.updated_at || claim?.submitted_at
  }
  return ''
}

function buildProgressSteps(approvalMeta, workflowNode, claim = {}, options = {}) {
  const documentTypeCode = String(options.documentTypeCode || '').trim()
  const hasApplicationReturnStep = (
    documentTypeCode === DOCUMENT_TYPE_APPLICATION
    && Boolean(findLatestApplicationReturnEvent(claim))
    && approvalMeta.key === 'supplement'
  )
  const progressLabels =
    documentTypeCode === DOCUMENT_TYPE_APPLICATION
      ? hasApplicationReturnStep
        ? ['创建申请', '直属领导审批', '退回', '待提交']
        : APPLICATION_PROGRESS_LABELS
      : REIMBURSEMENT_PROGRESS_LABELS
  const currentIndex =
    documentTypeCode === DOCUMENT_TYPE_APPLICATION
      ? hasApplicationReturnStep
        ? 3
        : resolveApplicationProgressCurrentIndex(approvalMeta, workflowNode)
      : resolveProgressCurrentIndex(approvalMeta, workflowNode)
  const currentTime =
    approvalMeta.key === 'completed'
      ? '已完成'
      : approvalMeta.key === 'pending_payment'
        ? '待付款'
      : approvalMeta.key === 'supplement'
        ? '待补充'
        : approvalMeta.key === 'rejected'
          ? '已退回'
          : '进行中'

  return progressLabels.map((label, index) => {
    const displayLabel = resolveProgressDisplayLabel(label, documentTypeCode, claim, approvalMeta)
    if (approvalMeta.key === 'completed') {
      const stepMeta = buildCompletedStepMeta(claim, label)
      return {
        index: index + 1,
        label: displayLabel,
        rawLabel: label,
        time: stepMeta.time,
        detail: stepMeta.detail,
        title: stepMeta.title,
        done: true,
        active: true,
        current: false
      }
    }

    if (index < currentIndex) {
      const stepMeta = buildCompletedStepMeta(claim, label)
      return {
        index: index + 1,
        label: displayLabel,
        rawLabel: label,
        time: stepMeta.time,
        detail: stepMeta.detail,
        title: stepMeta.title,
        done: true,
        active: true,
        current: false
      }
    }

    if (index === currentIndex) {
      const stayDuration = formatDurationFrom(resolveCurrentStepStartedAt(claim, label))
      return {
        index: index + 1,
        label: displayLabel,
        rawLabel: label,
        time: stayDuration ? `停留 ${stayDuration}` : currentTime,
        detail: '',
        title: stayDuration ? `当前${displayLabel}已停留 ${stayDuration}` : currentTime,
        done: false,
        active: true,
        current: true
      }
    }

    return {
      index: index + 1,
      label: displayLabel,
      rawLabel: label,
      time: '待处理',
      detail: '',
      title: '待处理',
      done: false,
      active: false,
      current: false
    }
  })
}

function buildExpenseItems(claim, riskSummary) {
  if (!Array.isArray(claim?.items)) {
    return []
  }

  const sortedItems = [...claim.items].sort((left, right) => {
    const leftType = normalizeExpenseType(left?.item_type)
    const rightType = normalizeExpenseType(right?.item_type)
    return Number(SYSTEM_GENERATED_EXPENSE_TYPES.has(leftType)) - Number(SYSTEM_GENERATED_EXPENSE_TYPES.has(rightType))
  })
  const travelTimeLabelMap = buildTravelTimeLabelMap(sortedItems, claim)

  return sortedItems.map((item, index) => {
    const invoiceId = String(item?.invoice_id || '').trim()
    const attachmentName = resolveAttachmentDisplayName(invoiceId)
    const attachments = invoiceId ? [attachmentName || invoiceId] : []
    const itemType = normalizeExpenseType(item?.item_type || claim?.expense_type)
    const isSystemGenerated = Boolean(item?.is_system_generated || SYSTEM_GENERATED_EXPENSE_TYPES.has(itemType))
    const id = resolveExpenseItemViewId(item, index, claim)
    const itemTypeLabel = resolveTypeLabel(itemType)
    const itemLocation = String(item?.item_location || '').trim()
    const itemReason = String(item?.item_reason || '').trim()
    const itemAmount = parseNumber(item?.item_amount)
    const itemAmountDisplay = itemAmount > 0 ? formatAmount(itemAmount) : '待补充'

    return {
      id,
      time: formatDate(item?.item_date) || '待补充',
      itemDate: formatDate(item?.item_date) || '',
      filledAt: formatDateTime(item?.created_at) || '待同步',
      itemType,
      itemReason,
      itemLocation,
      itemAmount,
      invoiceId,
      isSystemGenerated,
      dayLabel: resolveExpenseTimeLabel({
        id,
        itemType,
        isSystemGenerated,
        claim,
        travelTimeLabelMap
      }),
      name: itemTypeLabel,
      category: itemTypeLabel,
      desc: itemReason || '待补充',
      detail: resolveExpenseDescriptionDetail(itemType, itemLocation),
      amount: itemAmountDisplay,
      status: isSystemGenerated ? '系统计算' : attachments.length ? '已识别' : '待补充',
      tone: isSystemGenerated ? 'system' : attachments.length ? 'ok' : 'bad',
      attachmentStatus: isSystemGenerated ? '无需附件' : attachments.length ? '已关联票据' : '未上传',
      attachmentHint: isSystemGenerated ? '根据出差天数与职级自动测算' : attachments.length ? attachments[0] : '仅支持上传 1 张 JPG、PNG、PDF 单据',
      attachmentTone: isSystemGenerated ? 'system' : attachments.length ? 'ok' : 'missing',
      attachments,
      riskLabel: riskSummary === '无' ? '无' : '待关注',
      riskText: riskSummary === '无' ? '' : riskSummary,
      riskTone: riskSummary === '无' ? 'low' : 'medium'
    }
  })
}

export function mapExpenseClaimToRequest(claim) {
  const typeCode = String(claim?.expense_type || '').trim() || 'other'
  const typeLabel = resolveTypeLabel(typeCode)
  const documentTypeMeta = resolveDocumentTypeMeta(claim, typeCode)
  const isApplicationDocument = documentTypeMeta.documentTypeCode === DOCUMENT_TYPE_APPLICATION
  const approvalMeta = resolveApprovalMeta(claim?.status)
  const workflowNode = resolveWorkflowNode(claim, approvalMeta, isApplicationDocument)
  const invoiceCount = Math.max(0, parseNumber(claim?.invoice_count))
  const riskSummary = buildRiskSummary(claim?.risk_flags_json)
  const expenseItems = buildExpenseItems(claim, riskSummary)
  const applyDateTime = claim?.submitted_at || claim?.created_at

  return {
    id: String(claim?.claim_no || claim?.id || '').trim(),
    claimNo: String(claim?.claim_no || claim?.id || '').trim(),
    claimId: String(claim?.id || '').trim(),
    status: String(claim?.status || '').trim(),
    person: String(claim?.employee_name || '').trim() || '待补充',
    dept: String(claim?.department_name || '').trim() || '待补充',
    departmentName: String(claim?.department_name || '').trim() || '待补充',
    employeeName: String(claim?.employee_name || '').trim() || '待补充',
    employeePosition: String(claim?.employee_position || '').trim(),
    employeeGrade: String(claim?.employee_grade || '').trim(),
    managerName: resolveDisplayName(claim?.manager_name),
    roleLabels: Array.isArray(claim?.role_labels) ? claim.role_labels.filter(Boolean) : [],
    entity: '',
    typeCode,
    typeLabel,
    ...documentTypeMeta,
    detailVariant: typeCode === 'travel' || typeCode === 'travel_application' ? 'travel' : 'general',
    title: String(claim?.reason || '').trim() || (isApplicationDocument ? typeLabel : `${typeLabel}报销`),
    sceneLabel: typeLabel,
    sceneTarget: String(claim?.location || '').trim() || '待补充',
    location: String(claim?.location || '').trim() || '待补充',
    relatedCustomer: '',
    occurredDisplay: buildOccurredDisplay(claim),
    occurredAt: claim?.occurred_at || '',
    applyTime: formatDateTime(applyDateTime) || '待补充',
    submittedAt: applyDateTime || '',
    createdAt: claim?.created_at || '',
    updatedAt: claim?.updated_at || '',
    amount: parseNumber(claim?.amount),
    riskFlags: Array.isArray(claim?.risk_flags_json) ? claim.risk_flags_json : [],
    invoiceCount,
    workflowNode,
    approvalKey: approvalMeta.key,
    approvalStatus: approvalMeta.label,
    approvalTone: approvalMeta.tone,
    secondaryStatusLabel: isApplicationDocument ? '申请材料' : (typeCode === 'travel' ? '行程状态' : '票据状态'),
    secondaryStatusValue: isApplicationDocument
      ? approvalMeta.key === 'supplement'
        ? '领导已退回，待重新提交'
        : '已进入审批流程'
      : (invoiceCount > 0 ? `已关联 ${invoiceCount} 张票据` : '待上传票据'),
    secondaryStatusTone: isApplicationDocument
      ? approvalMeta.key === 'supplement' ? 'warning' : 'success'
      : (invoiceCount > 0 ? 'success' : 'warning'),
    riskSummary,
    attachmentSummary: isApplicationDocument ? '申请单' : (invoiceCount > 0 ? `${invoiceCount} 张票据` : '无'),
    expenseTableSummary: isApplicationDocument
      ? '预计金额已随申请提交'
      : expenseItems.length
      ? (invoiceCount > 0
        ? `共 ${expenseItems.length} 条费用明细，已关联 ${invoiceCount} 张票据`
        : `共 ${expenseItems.length} 条费用明细，待补充票据`)
      : '暂无费用明细',
    note: String(claim?.reason || '').trim(),
    progressSteps: buildProgressSteps(approvalMeta, workflowNode, claim, {
      documentTypeCode: documentTypeMeta.documentTypeCode
    }),
    expenseItems
  }
}

function getWeekStart(date) {
  const nextDate = new Date(date)
  const day = nextDate.getDay() || 7
  nextDate.setHours(0, 0, 0, 0)
  nextDate.setDate(nextDate.getDate() - day + 1)
  return nextDate
}

function getRecentDaysStart(date, days) {
  const nextDate = new Date(date)
  nextDate.setHours(0, 0, 0, 0)
  nextDate.setDate(nextDate.getDate() - Math.max(0, Number(days || 1) - 1))
  return nextDate
}

function resolveRangeMatch(activeRange, item) {
  if (activeRange === 'custom' || activeRange === '本月') {
    if (activeRange !== '本月') {
      return true
    }
  }

  const targetDate = toDate(item?.submittedAt || item?.createdAt || item?.occurredAt)
  if (!targetDate) {
    return true
  }

  const now = new Date()
  const targetDay = formatDate(targetDate)

  if (activeRange === '今日') {
    return targetDay === formatDate(now)
  }

  if (activeRange === '近10日') {
    const recentStart = getRecentDaysStart(now, 10)
    return targetDate >= recentStart && targetDate <= now
  }

  if (activeRange === '本周') {
    const weekStart = getWeekStart(now)
    const nextWeekStart = new Date(weekStart)
    nextWeekStart.setDate(nextWeekStart.getDate() + 7)
    return targetDate >= weekStart && targetDate < nextWeekStart
  }

  if (activeRange === '本月') {
    return (
      targetDate.getFullYear() === now.getFullYear()
      && targetDate.getMonth() === now.getMonth()
    )
  }

  return true
}

export function useRequests() {
  const requests = ref([])
  const loading = ref(false)
  const error = ref('')
  const search = ref('')
  const filters = reactive({ entity: '全部主体', category: '全部类型', risk: '全部状态' })
  const ranges = ['今日', '近10日', '本周', '本月']
  const activeRange = ref('近10日')

  const filteredRequests = computed(() => {
    const key = search.value.trim().toLowerCase()

    return requests.value.filter((item) => {
      const searchText = [
        item.id,
        item.person,
        item.typeLabel,
        item.title,
        item.sceneTarget,
        item.riskSummary
      ]
        .filter(Boolean)
        .join('')
        .toLowerCase()

      const matchesSearch = !key || searchText.includes(key)
      const matchesRange = resolveRangeMatch(activeRange.value, item)

      return matchesSearch && matchesRange
    })
  })

  async function reload() {
    loading.value = true
    error.value = ''

    try {
      const payload = await fetchExpenseClaims()
      requests.value = Array.isArray(payload) ? payload.map((item) => mapExpenseClaimToRequest(item)) : []
    } catch (nextError) {
      requests.value = []
      error.value = nextError instanceof Error ? nextError.message : '个人报销列表加载失败。'
    } finally {
      loading.value = false
    }
  }

  function approveRequest(request) {
    return `${request.id} 未执行本地状态变更，列表当前只展示后端真实数据。`
  }

  function rejectRequest(request) {
    return `${request.id} 未执行本地状态变更，列表当前只展示后端真实数据。`
  }

  void reload()

  return {
    requests,
    loading,
    error,
    search,
    filters,
    ranges,
    activeRange,
    filteredRequests,
    approveRequest,
    rejectRequest,
    reload
  }
}
