import { isApplicationRequestLike } from './documentClassification.js'
import { canProcessApprovalRequest } from './approvalInbox.js'

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

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

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

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

function isCurrentMonth(dateValue) {
  const date = toDate(dateValue)
  if (!date) {
    return false
  }

  const now = new Date()
  return date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth()
}

function resolveClaimDate(request) {
  return request?.submittedAt || request?.createdAt || request?.occurredAt || ''
}

export function belongsToCurrentUser(request, currentUser) {
  const person = String(request?.person || request?.employeeName || '').trim()
  if (!person) {
    return false
  }

  const names = [
    String(currentUser?.name || '').trim(),
    String(currentUser?.username || '').trim()
  ].filter(Boolean)

  return names.some((name) => name === person)
}

function belongsToWorkbenchProgressScope(request, currentUser) {
  if (belongsToCurrentUser(request, currentUser)) {
    return true
  }

  return normalizeText(request?.approvalKey) === 'in_progress'
    && canProcessApprovalRequest(request, currentUser)
}

export function hasHighRiskFlag(request) {
  const riskFlags = Array.isArray(request?.riskFlags) ? request.riskFlags : []

  if (riskFlags.some((item) => String(item?.severity || '').trim().toLowerCase() === 'high')) {
    return true
  }

  const summary = String(request?.riskSummary || '').trim()
  return summary.includes('高')
}

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

function formatPercent(value) {
  const percent = Number(value)
  if (!Number.isFinite(percent)) {
    return '0%'
  }

  return `${percent.toFixed(percent >= 10 || percent === 0 ? 0 : 1)}%`
}

function padDatePart(value) {
  return String(value).padStart(2, '0')
}

function formatMonthKey(date) {
  return `${date.getFullYear()}-${padDatePart(date.getMonth() + 1)}`
}

function formatMonthLabel(date) {
  return `${date.getMonth() + 1}月`
}

function shiftMonth(date, offset) {
  return new Date(date.getFullYear(), date.getMonth() + offset, 1)
}

function resolveMonthStart(date) {
  return new Date(date.getFullYear(), date.getMonth(), 1)
}

function formatDateTimeLabel(value) {
  if (value instanceof Date) {
    return [
      value.getFullYear(),
      padDatePart(value.getMonth() + 1),
      padDatePart(value.getDate())
    ].join('-') + ` ${padDatePart(value.getHours())}:${padDatePart(value.getMinutes())}`
  }

  const text = normalizeText(value)
  if (!text) {
    return '暂无时间'
  }

  const match = /^(\d{4})-(\d{2})-(\d{2})(?:[T\s](\d{2}):(\d{2}))?/.exec(text)
  if (match) {
    return match[4] ? `${match[1]}-${match[2]}-${match[3]} ${match[4]}:${match[5]}` : `${match[1]}-${match[2]}-${match[3]}`
  }

  return text
}

function formatDurationLabel(milliseconds) {
  const duration = Number(milliseconds)
  if (!Number.isFinite(duration) || duration <= 0) {
    return '暂无耗时'
  }

  const minute = 60 * 1000
  const hour = 60 * minute
  const day = 24 * hour

  if (duration < hour) {
    return `${Math.max(1, Math.round(duration / minute))}分钟`
  }
  if (duration < day) {
    return `${Math.max(1, Math.round(duration / hour))}小时`
  }

  return `${Math.ceil(duration / day)}天`
}

function resolveRequestIdentity(request) {
  return normalizeText(request?.claimNo || request?.claim_no || request?.id || request?.claimId)
}

function resolveRequestTarget(request) {
  return {
    type: 'document',
    id: normalizeText(request?.claimId || request?.id),
    claimNo: resolveRequestIdentity(request)
  }
}

function resolveApplicantLabel(request) {
  return normalizeText(
    request?.person
    || request?.employeeName
    || request?.employee_name
    || request?.applicant
    || request?.profileName
  ) || '待补充'
}

function resolveStatusTone(approvalKey) {
  if (approvalKey === 'supplement' || approvalKey === 'rejected') return 'danger'
  if (approvalKey === 'draft') return 'success'
  if (approvalKey === 'pending_payment') return 'warning'
  if (approvalKey === 'in_progress') return 'info'
  return 'muted'
}

function resolveDocumentTypeLabel(request, requestId, title) {
  const explicitLabel = normalizeText(request?.documentTypeLabel || request?.document_type_label)
  const normalizedRequestId = normalizeText(requestId).toUpperCase()

  if (
    isApplicationRequestLike(request)
    || explicitLabel.includes('申请')
    || title.includes('申请')
    || normalizedRequestId.startsWith('SQ')
    || normalizedRequestId.startsWith('CL')
  ) {
    return '申请单'
  }

  return explicitLabel || '报销单'
}

function resolveTodoAction(request) {
  const approvalKey = normalizeText(request?.approvalKey)
  const status = normalizeText(request?.status || request?.approvalStatus)

  if (approvalKey === 'supplement' || approvalKey === 'rejected') {
    return {
      title: '补充或修改单据',
      status: approvalKey === 'rejected' ? '退回修改' : '待补充',
      statusTone: 'danger',
      iconKey: 'receipts',
      color: 'var(--danger)',
      accent: 'var(--danger-soft)'
    }
  }

  if (approvalKey === 'draft' || /draft|草稿|待提交/i.test(status)) {
    return {
      title: '提交草稿单据',
      status: '待提交',
      statusTone: 'success',
      iconKey: 'travelDraft',
      color: 'var(--theme-primary)',
      accent: 'var(--theme-primary-soft)'
    }
  }

  return null
}

function buildTodoItems(ownedRequests) {
  return ownedRequests
    .map((request) => {
      const action = resolveTodoAction(request)
      if (!action) {
        return null
      }

      const requestId = resolveRequestIdentity(request)
      const title = normalizeText(request?.title || request?.note || request?.sceneLabel) || requestId

      return {
        ...action,
        id: requestId,
        requestId,
        title: action.title,
        description: `${requestId || '单据'} · ${title || '费用单据'}`,
        due: normalizeText(request?.updatedAt || request?.applyTime || request?.submittedAt) || '待处理',
        target: resolveRequestTarget(request),
        prompt: `帮我处理 ${requestId || title}：${action.status}`
      }
    })
    .filter(Boolean)
    .sort((left, right) => normalizeText(right.due).localeCompare(normalizeText(left.due)))
}

function resolveProgressStatusTone(approvalKey, statusText = '') {
  const status = String(statusText || '').trim()
  if (approvalKey === 'completed' || /完成|结束|通过/i.test(status)) return 'muted'
  if (approvalKey === 'pending_payment' || /付款|支付/i.test(status)) return 'warning'
  if (approvalKey === 'supplement' || approvalKey === 'rejected' || /退回|驳回|修改/i.test(status)) return 'danger'
  return 'success'
}

function resolveCurrentProgressIndex(steps) {
  const currentIndex = steps.findIndex((step) => step?.current)
  if (currentIndex >= 0) {
    return currentIndex
  }

  const activeIndex = steps.findLastIndex((step) => step?.active || step?.done)
  return Math.max(0, activeIndex)
}

export function buildAdjacentProgressSteps(steps = [], windowSize = 4) {
  const rows = Array.isArray(steps) ? steps : []
  if (!rows.length) {
    return []
  }

  const currentIndex = resolveCurrentProgressIndex(rows)
  const safeWindowSize = Math.max(1, Number(windowSize) || 4)
  let start = Math.max(0, currentIndex - 1)
  let end = Math.min(rows.length, start + safeWindowSize)

  if (end - start < safeWindowSize) {
    start = Math.max(0, end - safeWindowSize)
  }

  return rows.slice(start, end).map((step) => ({
    label: normalizeText(step.label || step.rawLabel),
    done: Boolean(step.done),
    current: Boolean(step.current),
    title: normalizeText(step.title || step.time || step.detail)
  }))
}

const FALLBACK_APPLICATION_PROGRESS_LABELS = Object.freeze([
  '创建申请',
  '直属领导审批',
  '关联单据状态',
  '已归档'
])
const FALLBACK_REIMBURSEMENT_PROGRESS_LABELS = Object.freeze([
  '关联单据',
  '待提交',
  '直属领导审批',
  '财务审批',
  '待付款',
  '已付款',
  '已归档'
])

function resolveFallbackProgressCurrentIndex(labels, request, documentTypeLabel) {
  const approvalKey = normalizeText(request?.approvalKey)
  const status = normalizeText(request?.approvalStatus || request?.status || request?.workflowNode)

  if (documentTypeLabel === '申请单') {
    if (/归档/.test(status)) return labels.indexOf('已归档')
    if (approvalKey === 'completed' || /完成|通过/.test(status)) return labels.indexOf('关联单据状态')
    if (/直属领导|领导审批|负责人/.test(status)) return labels.indexOf('直属领导审批')
    return 0
  }

  if (approvalKey === 'completed' || /归档|已付款|完成/.test(status)) return labels.indexOf('已归档')
  if (approvalKey === 'pending_payment' || /待付款|待支付/.test(status)) return labels.indexOf('待付款')
  if (/财务/.test(status)) return labels.indexOf('财务审批')
  if (/直属领导|领导审批|负责人/.test(status)) return labels.indexOf('直属领导审批')
  return labels.indexOf('待提交')
}

function buildFallbackProgressSteps(request, documentTypeLabel) {
  const labels = documentTypeLabel === '申请单'
    ? FALLBACK_APPLICATION_PROGRESS_LABELS
    : FALLBACK_REIMBURSEMENT_PROGRESS_LABELS
  const currentIndex = Math.max(0, resolveFallbackProgressCurrentIndex(labels, request, documentTypeLabel))

  return labels.map((label, index) => ({
    label,
    rawLabel: label,
    done: index < currentIndex,
    active: index <= currentIndex,
    current: index === currentIndex,
    title: index === currentIndex ? '进行中' : index < currentIndex ? '已完成' : '待处理'
  }))
}

function buildProgressItems(ownedRequests) {
  return ownedRequests
    .map((request) => {
      const requestId = resolveRequestIdentity(request)
      const title = normalizeText(request?.title || request?.note || request?.sceneLabel) || '费用单据'
      const documentTypeLabel = resolveDocumentTypeLabel(request, requestId, title)
      const sourceSteps = Array.isArray(request?.progressSteps) && request.progressSteps.length
        ? request.progressSteps
        : buildFallbackProgressSteps(request, documentTypeLabel)
      const steps = buildAdjacentProgressSteps(sourceSteps, 4)
      const currentStep = steps.find((step) => step.current)

      const status = normalizeText(request?.approvalStatus || currentStep?.label) || '处理中'

      return {
        id: requestId,
        requestId,
        title,
        documentTypeLabel,
        applicantLabel: resolveApplicantLabel(request),
        expenseTypeLabel: resolveExpenseCategory(request),
        amount: formatCurrency(request?.amount),
        status,
        statusTone: resolveProgressStatusTone(normalizeText(request?.approvalKey), status),
        updatedAt: normalizeText(request?.updatedAt || request?.submittedAt || request?.createdAt || request?.applyTime),
        steps,
        target: resolveRequestTarget(request),
        prompt: `查询 ${requestId || title} 的单据进度`
      }
    })
    .sort((left, right) => normalizeText(right.updatedAt).localeCompare(normalizeText(left.updatedAt)))
}

function buildNotifications(todoItems, progressItems) {
  const todoNotifications = todoItems.map((item) => ({
    id: `todo:${item.requestId || item.description}`,
    title: item.status,
    description: item.description,
    time: item.due,
    unread: true,
    tone: item.statusTone,
    target: item.target,
    prompt: item.prompt
  }))

  const progressNotifications = progressItems
    .filter((item) => ['danger', 'warning'].includes(item.statusTone))
    .map((item) => ({
      id: `progress:${item.requestId || item.title}`,
      title: item.status,
      description: `${item.requestId || '单据'} · ${item.title}`,
      time: item.updatedAt || '最近更新',
      unread: false,
      tone: item.statusTone,
      target: item.target,
      prompt: item.prompt
    }))

  return [...todoNotifications, ...progressNotifications]
}

function resolveExpenseCategory(request) {
  const explicitCategory = normalizeText(
    request?.expenseCategory
      || request?.expense_category
      || request?.category
      || request?.expenseType
      || request?.expense_type
      || request?.type
  )
  if (explicitCategory) {
    return explicitCategory
  }

  const text = normalizeText([
    request?.sceneLabel,
    request?.title,
    request?.note,
    request?.description
  ].filter(Boolean).join(' '))

  if (/差旅|出差|交通|机票|火车|高铁|出租|网约车|住宿|酒店/i.test(text)) {
    return '差旅交通'
  }
  if (/招待|客户|餐饮|宴请|接待/i.test(text)) {
    return '业务招待'
  }
  if (/办公|采购|用品|设备|耗材/i.test(text)) {
    return '办公采购'
  }
  if (/培训|学习|课程|会议/i.test(text)) {
    return '培训会议'
  }
  if (/市场|活动|推广|宣传/i.test(text)) {
    return '市场活动'
  }

  return '其他费用'
}

function buildExpenseDistributionRows(ownedRequests) {
  const groups = new Map()

  for (const request of ownedRequests) {
    const category = resolveExpenseCategory(request)
    const amount = parseNumber(request?.amount)
    const group = groups.get(category) || {
      key: category,
      label: category,
      count: 0,
      amount: 0
    }

    group.count += 1
    group.amount += amount
    groups.set(category, group)
  }

  const totalAmount = Array.from(groups.values()).reduce((sum, item) => sum + item.amount, 0)
  const rows = Array.from(groups.values())
    .sort((left, right) => right.amount - left.amount || right.count - left.count)
    .slice(0, 6)

  return rows.map((item) => {
    const percent = totalAmount > 0 ? (item.amount / totalAmount) * 100 : 0
    return {
      ...item,
      amountLabel: formatCurrency(item.amount),
      percent,
      percentLabel: formatPercent(percent)
    }
  })
}

function collectRequestDates(request) {
  const candidates = [
    request?.createdAt,
    request?.submittedAt,
    request?.updatedAt,
    request?.applyTime,
    request?.occurredAt
  ]

  const steps = Array.isArray(request?.progressSteps) ? request.progressSteps : []
  for (const step of steps) {
    candidates.push(step?.time, step?.createdAt, step?.updatedAt, step?.timestamp)
  }

  return candidates
    .map((item) => toDate(item))
    .filter(Boolean)
    .sort((left, right) => left.getTime() - right.getTime())
}

function buildExpenseProcessingRows(ownedRequests) {
  return ownedRequests
    .map((request) => {
      const dates = collectRequestDates(request)
      const requestId = resolveRequestIdentity(request)
      const title = normalizeText(request?.title || request?.note || request?.sceneLabel) || '费用单据'
      const startedAt = dates[0] || toDate(request?.createdAt || request?.submittedAt)
      const latestAt = dates[dates.length - 1] || toDate(request?.updatedAt || request?.submittedAt || request?.createdAt)
      const stepCount = Array.isArray(request?.progressSteps) ? request.progressSteps.length : 0

      const status = normalizeText(request?.approvalStatus || request?.status) || '处理中'

      return {
        id: requestId || title,
        requestId,
        title,
        status,
        statusTone: resolveProgressStatusTone(normalizeText(request?.approvalKey), status),
        startedAt: startedAt ? formatDateTimeLabel(startedAt) : '暂无开始时间',
        updatedAt: latestAt ? formatDateTimeLabel(latestAt) : '暂无更新时间',
        durationLabel: startedAt && latestAt ? formatDurationLabel(latestAt.getTime() - startedAt.getTime()) : '暂无耗时',
        stepCount,
        sortTime: latestAt ? latestAt.getTime() : 0
      }
    })
    .sort((left, right) => right.sortTime - left.sortTime)
    .slice(0, 6)
    .map(({ sortTime, ...item }) => item)
}

function buildExpenseOperationRows(todoItems, notifications, progressItems) {
  const rows = []

  for (const item of todoItems) {
    rows.push({
      id: `todo:${item.requestId || item.description}`,
      action: item.status || item.title,
      detail: item.description,
      time: item.due,
      tone: item.statusTone || 'info',
      source: '待办'
    })
  }

  for (const item of notifications) {
    rows.push({
      id: `notice:${item.id}`,
      action: item.title,
      detail: item.description,
      time: item.time,
      tone: item.tone || 'info',
      source: item.unread ? '未读提醒' : '系统提醒'
    })
  }

  for (const item of progressItems.slice(0, 6)) {
    rows.push({
      id: `progress:${item.requestId || item.id}`,
      action: item.status,
      detail: `${item.requestId || item.id || '单据'} · ${item.title}`,
      time: item.updatedAt || '最近更新',
      tone: item.statusTone || 'info',
      source: '进度'
    })
  }

  const seen = new Set()
  return rows
    .filter((item) => {
      const key = [item.action, item.detail, item.time].join('|')
      if (seen.has(key)) {
        return false
      }
      seen.add(key)
      return true
    })
    .sort((left, right) => normalizeText(right.time).localeCompare(normalizeText(left.time)))
    .slice(0, 8)
}

function buildMonthlyAmountMap(ownedRequests) {
  const rows = new Map()

  for (const request of ownedRequests) {
    const date = toDate(resolveClaimDate(request))
    if (!date) {
      continue
    }

    const key = formatMonthKey(date)
    rows.set(key, (rows.get(key) || 0) + parseNumber(request?.amount))
  }

  return rows
}

function resolveTrendAnchorDate(ownedRequests) {
  const dates = ownedRequests
    .map((request) => toDate(resolveClaimDate(request)))
    .filter(Boolean)
    .sort((left, right) => right.getTime() - left.getTime())

  return resolveMonthStart(dates[0] || new Date())
}

function buildReimbursementTrendRows(ownedRequests) {
  const monthlyAmountMap = buildMonthlyAmountMap(ownedRequests)
  const anchor = resolveTrendAnchorDate(ownedRequests)

  return Array.from({ length: 6 }, (_, index) => {
    const month = shiftMonth(anchor, index - 5)
    const previousMonth = shiftMonth(month, -12)
    const key = formatMonthKey(month)
    const previousKey = formatMonthKey(previousMonth)
    const amount = monthlyAmountMap.get(key) || 0
    const previousAmount = monthlyAmountMap.get(previousKey) || 0

    return {
      key,
      label: formatMonthLabel(month),
      amount,
      amountLabel: formatCurrency(amount),
      previousKey,
      previousAmount,
      previousAmountLabel: formatCurrency(previousAmount)
    }
  })
}

export function buildWorkbenchSummary(requests, currentUser) {
  const allRequests = Array.isArray(requests)
    ? requests
    : []
  const ownedRequests = allRequests.filter((item) => belongsToCurrentUser(item, currentUser))
  const progressRequests = allRequests.filter((item) => belongsToWorkbenchProgressScope(item, currentUser))

  const monthlyClaims = ownedRequests.filter((item) => isCurrentMonth(resolveClaimDate(item)))

  const monthlyCount = monthlyClaims.length
  const monthlyAmount = monthlyClaims.reduce((sum, item) => sum + parseNumber(item.amount), 0)
  const totalCount = ownedRequests.length
  const totalAmount = ownedRequests.reduce((sum, item) => sum + parseNumber(item.amount), 0)
  const inReviewCount = ownedRequests.filter((item) => item.approvalKey === 'in_progress').length
  const pendingPaymentCount = ownedRequests.filter((item) => {
    const status = String(item.status || item.approvalStatus || '').trim()
    return status.includes('待付款') || status.includes('待支付')
  }).length
  const completedCount = ownedRequests.filter((item) => item.approvalKey === 'completed').length
  const returnCount = ownedRequests.filter((item) => item.approvalKey === 'rejected').length
  const highRiskCount = monthlyClaims.filter((item) => hasHighRiskFlag(item)).length
  const todoItems = buildTodoItems(ownedRequests)
  const progressItems = buildProgressItems(progressRequests)
  const notifications = buildNotifications(todoItems, progressItems)
  const expenseStatsDetail = {
    distributionRows: buildExpenseDistributionRows(ownedRequests),
    processingRows: buildExpenseProcessingRows(ownedRequests),
    operationRows: buildExpenseOperationRows(todoItems, notifications, progressItems)
  }

  return {
    monthlyCount,
    monthlyAmount,
    monthlyAmountLabel: formatCurrency(monthlyAmount),
    totalCount,
    totalAmount,
    totalAmountLabel: formatCurrency(totalAmount),
    inReviewCount,
    pendingPaymentCount,
    completedCount,
    returnCount,
    highRiskCount,
    todoItems,
    progressItems,
    reimbursementTrendRows: buildReimbursementTrendRows(ownedRequests),
    notifications,
    expenseStatsDetail,
    unreadNotificationCount: notifications.filter((item) => item.unread).length
  }
}
