import { isApplicationDocumentNo } from '../../utils/documentClassification.js'
import { filterActionableRiskFlags, normalizeRiskFlagTone } from '../../utils/riskFlags.js'
import {
  DOCUMENT_TYPE_APPLICATION,
  DOCUMENT_TYPE_EXPENSE_APPLICATION,
  DOCUMENT_TYPE_REIMBURSEMENT,
  resolveDocumentTypeLabel
} from '../../constants/documentProtocol.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 STANDARD_ADJUSTMENT_RISK_SOURCE = 'reimbursement_standard_adjustment'
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_BACKED_EXPENSE_TYPES = new Set([
  'train_ticket',
  'flight_ticket',
  'ship_ticket',
  'ferry_ticket',
  'hotel_ticket',
  'ride_ticket'
])
const RELATED_APPLICATION_STEP_LABEL = '关联单据'
const APPLICATION_LINK_STATUS_STEP_LABEL = '关联单据状态'
const APPLICATION_ARCHIVE_STAGE_LABEL = '申请归档'
const ARCHIVED_STEP_LABEL = '已归档'

const REIMBURSEMENT_PROGRESS_LABELS = [
  RELATED_APPLICATION_STEP_LABEL,
  '待提交',
  '直属领导审批',
  '财务审批',
  '待付款',
  '已付款',
  ARCHIVED_STEP_LABEL
]

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

const APPLICATION_PROGRESS_LABELS_WITHOUT_BUDGET = [
  '创建申请',
  '直属领导审批',
  APPLICATION_LINK_STATUS_STEP_LABEL,
  ARCHIVED_STEP_LABEL
]

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

function parseOptionalAmount(value) {
  if (value === null || value === undefined || String(value).trim() === '') {
    return null
  }
  const amount = Number(value)
  return Number.isFinite(amount) && amount >= 0 ? amount : null
}


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 === DOCUMENT_TYPE_EXPENSE_APPLICATION
    || isApplicationDocumentNo(claimNo)
    || normalizedType === 'application'
    || normalizedType.endsWith('_application')

  return isApplication
    ? { documentTypeCode: DOCUMENT_TYPE_APPLICATION, documentTypeLabel: resolveDocumentTypeLabel(DOCUMENT_TYPE_APPLICATION) }
    : { documentTypeCode: DOCUMENT_TYPE_REIMBURSEMENT, documentTypeLabel: resolveDocumentTypeLabel(DOCUMENT_TYPE_REIMBURSEMENT) }
}

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

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 (
      isApplicationDocument
      && approvalMeta.key === 'completed'
      && (
        rawNode === '审批完成'
        || rawNode.includes('审批完成')
        || rawNode.includes('申请完成')
      )
    ) {
      return APPLICATION_LINK_STATUS_STEP_LABEL
    }
    if (rawNode === '审批流转' || rawNode.includes('AI预审') || rawNode.includes('AI验审')) {
      return approvalMeta.key === 'draft' || approvalMeta.key === 'supplement' ? '待提交' : '直属领导审批'
    }
    if (rawNode === '待补充') {
      return '待提交'
    }
    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 ? APPLICATION_LINK_STATUS_STEP_LABEL : normalizedStatus === 'paid' ? '已付款' : '归档入账'
  }

  return '直属领导审批'
}

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 ''
}

const RISK_TONE_LABELS = {
  high: '高风险',
  medium: '中风险',
  low: '低风险'
}

function resolveHighestRiskTone(flags) {
  const tones = flags.map((item) => normalizeRiskFlagTone(item)).filter(Boolean)
  if (tones.includes('high')) {
    return 'high'
  }
  if (tones.includes('medium')) {
    return 'medium'
  }
  if (tones.includes('low')) {
    return 'low'
  }
  return 'low'
}

function buildRiskMeta(riskFlags) {
  if (!Array.isArray(riskFlags) || !riskFlags.length) {
    return { summary: '无', tone: 'low', label: '无' }
  }

  const actionableFlags = filterActionableRiskFlags(riskFlags)
  const items = actionableFlags.map((item) => stringifyRiskFlag(item)).filter(Boolean)
  if (!items.length) {
    return { summary: '无', tone: 'low', label: '无' }
  }

  const tone = resolveHighestRiskTone(actionableFlags)
  return {
    summary: items.join('；'),
    tone,
    label: RISK_TONE_LABELS[tone] || '待关注'
  }
}

function buildRiskSummary(riskFlags) {
  return buildRiskMeta(riskFlags).summary
}

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 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 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
}

export {
  APPLICATION_ARCHIVE_STAGE_LABEL,
  APPLICATION_LINK_STATUS_STEP_LABEL,
  APPLICATION_PROGRESS_LABELS,
  APPLICATION_PROGRESS_LABELS_WITHOUT_BUDGET,
  ARCHIVED_STEP_LABEL,
  DOCUMENT_BACKED_EXPENSE_TYPES,
  DOCUMENT_TYPE_APPLICATION,
  DOCUMENT_TYPE_REIMBURSEMENT,
  EXPENSE_TYPE_LABELS,
  HOTEL_DESCRIPTION_EXPENSE_TYPES,
  LOCATION_REQUIRED_EXPENSE_TYPES,
  LONG_DISTANCE_TRAVEL_EXPENSE_TYPES,
  RELATED_APPLICATION_STEP_LABEL,
  REIMBURSEMENT_PROGRESS_LABELS,
  ROUTE_DESCRIPTION_EXPENSE_TYPES,
  STANDARD_ADJUSTMENT_RISK_SOURCE,
  SYSTEM_GENERATED_EXPENSE_TYPES,
  buildOccurredDisplay,
  buildRiskMeta,
  buildRiskSummary,
  formatAmount,
  formatDate,
  formatDateTime,
  formatDurationFrom,
  getLatestEvent,
  getRiskFlags,
  isEmailLike,
  normalizeExpenseType,
  normalizeText,
  parseNumber,
  parseOptionalAmount,
  resolveApprovalMeta,
  resolveDisplayName,
  resolveDocumentTypeMeta,
  resolveTypeLabel,
  resolveWorkflowNode,
  toDate
}
