import { buildApplicationFieldsFromOntology } from './expenseApplicationOntology.js'

const APPLICATION_SESSION_TYPE = 'application'
const APPLICATION_CREATE_PATTERN = /申请|事前|前置|预算|出差|差旅|采购|会务|会议|培训|办公用品|交通|住宿/
const APPLICATION_QUERY_PATTERN = /查询|状态|进度|列表|有哪些|材料清单|需要哪些|制度|标准|规则|怎么规定/

export const APPLICATION_PREVIEW_FIELD_DEFINITIONS = [
  { key: 'applicationType', label: '申请类型' },
  { key: 'grade', label: '职级', highlight: true, editable: false, required: false },
  { key: 'time', label: '发生时间' },
  { key: 'location', label: '地点' },
  { key: 'reason', label: '事由' },
  { key: 'days', label: '天数' },
  { key: 'transportMode', label: '出行方式' },
  { key: 'lodgingDailyCap', label: '住宿上限/天', highlight: true, editable: false, required: false },
  { key: 'subsidyDailyCap', label: '补贴标准/天', highlight: true, editable: false, required: false },
  { key: 'transportPolicy', label: '交通费用口径', highlight: true, editable: false, required: false },
  { key: 'policyEstimate', label: '规则测算参考', highlight: true, editable: false, required: false },
  { key: 'amount', label: '用户预估费用', highlight: true }
]

export const APPLICATION_TRANSPORT_MODE_OPTIONS = ['火车', '飞机', '轮船']

const APPLICATION_POLICY_PENDING_TEXT = '填写地点和天数后自动测算'
const APPLICATION_TRANSPORT_REIMBURSEMENT_TEXT = '车票、机票暂无实时价格接口，按真实票据实报实销'

function compactText(value) {
  return String(value || '').replace(/\s+/g, '')
}

function resolveFirstMatch(text, patterns = []) {
  for (const pattern of patterns) {
    const match = text.match(pattern)
    const value = String(match?.groups?.value || match?.[1] || '').trim()
    if (value) return value.replace(/[，。；;]$/, '')
  }
  return ''
}

function normalizeDateText(value) {
  return String(value || '').replace(/[/.]/g, '-').replace(/\s+/g, '')
}

function parseIsoDate(value) {
  const match = normalizeDateText(value).match(/^(20\d{2})-(\d{1,2})-(\d{1,2})$/)
  if (!match) return null
  const [, year, month, day] = match
  const date = new Date(Date.UTC(Number(year), Number(month) - 1, Number(day)))
  return Number.isNaN(date.getTime()) ? null : date
}

function formatIsoDate(date) {
  return date.toISOString().slice(0, 10)
}

function buildEndDateFromDays(startText, daysText = '') {
  const days = Number(String(daysText || '').replace(/[^\d]/g, ''))
  const start = parseIsoDate(startText)
  if (!days || !start) return ''
  const end = new Date(start.getTime())
  end.setUTCDate(end.getUTCDate() + days)
  return formatIsoDate(end)
}

function resolveDaysFromDateRange(rangeText) {
  const match = String(rangeText || '').match(/(20\d{2}[-/.]\d{1,2}[-/.]\d{1,2})\s*至\s*(20\d{2}[-/.]\d{1,2}[-/.]\d{1,2})/)
  if (!match) return ''
  const start = parseIsoDate(match[1])
  const end = parseIsoDate(match[2])
  if (!start || !end) return ''
  const diffDays = Math.round((end.getTime() - start.getTime()) / 86400000)
  return diffDays > 0 ? `${diffDays}天` : '1天'
}

function resolveApplicationType(text) {
  const compact = compactText(text)
  if (/差旅|出差|高铁|动车|火车|飞机|机票|航班|酒店|住宿/.test(compact)) return '差旅费用申请'
  if (/交通|出租车|的士|网约车|打车|通勤/.test(compact)) return '交通费用申请'
  if (/住宿|酒店/.test(compact)) return '住宿费用申请'
  if (/会务|会议|发布会|展会/.test(compact)) return '会务费用申请'
  if (/采购|办公用品|文具|设备|耗材/.test(compact)) return '采购费用申请'
  if (/培训|课程|学习/.test(compact)) return '培训费用申请'
  return '费用申请'
}

function resolveApplicationAmount(text) {
  const compact = compactText(text)
  const labeled = resolveFirstMatch(text, [
    /(?:用户预估费用|预估费用|申请金额|预计金额|预计费用|预计总费用|预算|金额|费用)\s*[:：]?\s*(?<value>\d+(?:\.\d+)?)\s*(?:元|块|人民币)?/u,
    /(?<value>\d+(?:\.\d+)?)\s*(?:元|块|人民币)/u
  ])
  if (labeled) return `${labeled}元`
  if (/不知道预算|预算不清楚|预算待定|待测算/.test(compact)) return '待测算'
  return ''
}

function resolveCurrentUserGrade(currentUser = {}) {
  return String(
    currentUser.grade
    || currentUser.employeeGrade
    || currentUser.employee_grade
    || currentUser.profileGrade
    || ''
  ).trim()
}

function parseApplicationDaysValue(value) {
  const match = String(value || '').match(/\d+/)
  const days = match ? Number(match[0]) : 0
  return Number.isFinite(days) && days > 0 ? Math.max(1, Math.floor(days)) : 0
}

function parseMoneyNumber(value) {
  const normalized = String(value ?? '').replace(/[^\d.-]/g, '')
  const amount = Number(normalized)
  return Number.isFinite(amount) ? amount : null
}

function formatPolicyMoney(value) {
  const amount = parseMoneyNumber(value)
  if (amount === null) return String(value || '').trim()
  return new Intl.NumberFormat('zh-CN', {
    minimumFractionDigits: 0,
    maximumFractionDigits: Number.isInteger(amount) ? 0 : 2
  }).format(amount)
}

function formatDailyPolicyMoney(value) {
  const display = formatPolicyMoney(value)
  return display ? `${display}元/天` : APPLICATION_POLICY_PENDING_TEXT
}

function buildTransportPolicyText(transportMode) {
  const mode = String(transportMode || '').trim()
  if (!mode) return APPLICATION_TRANSPORT_REIMBURSEMENT_TEXT
  return `${mode}票据暂无实时价格接口，按真实票据实报实销`
}

function ensureApplicationPolicyFields(fields = {}) {
  const nextFields = { ...fields }
  if (!String(nextFields.lodgingDailyCap || '').trim()) {
    nextFields.lodgingDailyCap = APPLICATION_POLICY_PENDING_TEXT
  }
  if (!String(nextFields.subsidyDailyCap || '').trim()) {
    nextFields.subsidyDailyCap = APPLICATION_POLICY_PENDING_TEXT
  }
  if (!String(nextFields.transportPolicy || '').trim() || /实报实销/.test(String(nextFields.transportPolicy || ''))) {
    nextFields.transportPolicy = buildTransportPolicyText(nextFields.transportMode)
  }
  if (!String(nextFields.policyEstimate || '').trim()) {
    nextFields.policyEstimate = APPLICATION_POLICY_PENDING_TEXT
  }
  return nextFields
}

function resolveApplicationDays(text) {
  const value = resolveFirstMatch(text, [
    /(?:出差|申请)?(?<value>\d+)\s*天/u,
    /(?<value>\d+)\s*(?:个)?工作日/u
  ])
  return value ? `${value}天` : ''
}

function resolveApplicationTime(text, daysText = '') {
  const range = text.match(
    /(20\d{2}[-/.]\d{1,2}[-/.]\d{1,2})\s*(?:至|到|~|—|–|--)\s*(20\d{2}[-/.]\d{1,2}[-/.]\d{1,2})/u
  )
  if (range) {
    return `${normalizeDateText(range[1])} 至 ${normalizeDateText(range[2])}`
  }

  const single = resolveFirstMatch(text, [
    /(?:发生时间|业务发生时间|申请时间|时间)\s*[:：]\s*(?<value>20\d{2}[-/.]\d{1,2}[-/.]\d{1,2})/u,
    /(?<value>20\d{2}[-/.]\d{1,2}[-/.]\d{1,2})/u
  ])
  if (!single) return ''
  const normalized = normalizeDateText(single)
  const endDate = buildEndDateFromDays(normalized, daysText)
  return endDate ? `${normalized} 至 ${endDate}` : normalized
}

function resolveApplicationLocation(text) {
  return resolveFirstMatch(text, [
    /(?:地点|业务地点|发生地点|目的地)\s*[:：]\s*(?<value>[^。；;\n]+)/u,
    /(?:去|到|前往)(?<value>[\u4e00-\u9fa5，,、]{2,24}?)(?:出差|支撑|支持|部署|开会|培训|拜访|验收|项目|客户|。|\s|$)/u
  ])
}

function resolveApplicationTransportMode(text) {
  const compact = compactText(text)
  if (/高铁|动车|火车|铁路/.test(compact)) return '火车'
  if (/飞机|机票|航班/.test(compact)) return '飞机'
  if (/轮船|船票|客轮|渡轮/.test(compact)) return '轮船'
  return ''
}

function stripKnownContextFromReason(value, context = {}) {
  const location = String(context.location || '').trim()
  let cleaned = String(value || '')
    .replace(/(?:发生时间|业务发生时间|申请时间|时间)\s*[:：]\s*(?=[，,、。；;\s]|$)/gu, '')
    .replace(/(?:地点|业务地点|发生地点|目的地)\s*[:：]\s*(?=[，,、。；;\s]|$)/gu, '')
    .replace(/20\d{2}[-/.]\d{1,2}[-/.]\d{1,2}\s*(?:至|到|~|—|–|--)\s*20\d{2}[-/.]\d{1,2}[-/.]\d{1,2}/gu, '')
    .replace(/20\d{2}[-/.]\d{1,2}[-/.]\d{1,2}/gu, '')
    .replace(/(?:出差|申请)?\d+\s*天/gu, '')
    .replace(/(?:用户预估费用|预估费用|预计总费用|预计费用|预计金额|申请金额|预算|金额|费用)\s*[:：]?\s*\d+(?:\.\d+)?\s*(?:元|块|人民币)?/gu, '')
    .replace(/(?:高铁|动车|火车|铁路|飞机|机票|航班|轮船|船票|客轮|渡轮|出租车|的士|网约车|打车|自驾)/gu, '')
    .replace(/[，,、。；;]+/g, '，')
    .replace(/^\s*(去|到|前往)/u, '')
    .replace(/^[，\s]+|[，\s]+$/g, '')
    .trim()

  if (location) {
    const escapedLocation = location.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
    cleaned = cleaned
      .replace(new RegExp(`^${escapedLocation}(?:出差)?(?:，|,|、)?`, 'u'), '')
      .replace(new RegExp(`^(?:去|到|前往)${escapedLocation}(?:出差)?(?:，|,|、)?`, 'u'), '')
      .trim()
  }

  return cleaned
}

function pickBusinessReasonSegment(text) {
  const segments = String(text || '')
    .split(/[，,、。；;\n]+/u)
    .map((item) => item.trim())
    .filter(Boolean)
  return segments.find((item) => /服务|支撑|支持|部署|实施|验收|拜访|对接|沟通|培训|会议|采购|安装|维护|上线|调试|项目/.test(item)) || ''
}

function resolveApplicationReason(text, context = {}) {
  const labeled = resolveFirstMatch(text, [
    /(?:事由|申请事由|出差事由|原因|用途)\s*[:：]\s*(?<value>[^，。；;\n]+)/u
  ])
  if (labeled) return stripKnownContextFromReason(labeled, context)
  const cleaned = String(text || '')
    .replace(/^\s*(我想|我要|帮我)?\s*(先)?\s*(发起|提交|申请)?\s*(一笔)?\s*(费用申请|申请)\s*/u, '')
  const withoutContext = stripKnownContextFromReason(cleaned, context)
  const businessSegment = pickBusinessReasonSegment(withoutContext)
  if (businessSegment) return stripKnownContextFromReason(businessSegment, context)
  return withoutContext
}

function isApplicationPreviewValueProvided(value) {
  const normalized = String(value || '').trim()
  return Boolean(normalized) && !['待测算', '待补充', '未知'].includes(normalized)
}

function resolveProvidedValue(value, fallback = '') {
  return isApplicationPreviewValueProvided(value) ? String(value).trim() : fallback
}

function normalizeApplicationTypeLabel(value, fallback = '') {
  const label = String(value || '').trim()
  if (!label || label === '其他费用') return fallback || '费用申请'
  if (label.endsWith('费用申请') || label.endsWith('申请')) return label
  if (label.endsWith('费用')) return `${label}申请`
  if (label.endsWith('费')) return `${label.slice(0, -1)}费用申请`
  return `${label}申请`
}

function normalizeTransportModeOption(value, fallback = '') {
  const text = String(value || '').trim()
  if (/飞机|机票|航班/.test(text)) return '飞机'
  if (/轮船|船票|客轮|渡轮|邮轮/.test(text)) return '轮船'
  if (/火车|高铁|动车|铁路|列车/.test(text)) return '火车'
  return APPLICATION_TRANSPORT_MODE_OPTIONS.includes(text) ? text : fallback
}

function normalizeAmountFromOntology(fields = {}, fallback = '') {
  const numericAmount = Number(fields.amount || 0)
  if (Number.isFinite(numericAmount) && numericAmount > 0) {
    return `${numericAmount}元`
  }

  const display = String(fields.amountDisplay || '').trim()
  if (display && display !== '待补充') {
    const normalized = display.replace(/^¥\s*/, '').replace(/,/g, '').trim()
    return normalized.endsWith('元') ? normalized : `${normalized}元`
  }

  return fallback
}

function buildMissingFields(fields) {
  return APPLICATION_PREVIEW_FIELD_DEFINITIONS
    .filter((item) => item.key !== 'applicationType' && item.required !== false)
    .filter((item) => !isApplicationPreviewValueProvided(fields?.[item.key]))
    .map((item) => item.label)
}

export function buildApplicationPolicyEstimateRequest(preview = {}, currentUser = {}) {
  const normalized = normalizeApplicationPreview(preview)
  const fields = normalized.fields || {}
  const days = parseApplicationDaysValue(fields.days)
  const location = String(fields.location || '').trim()
  const grade = String(fields.grade || resolveCurrentUserGrade(currentUser)).trim()
  const applicationType = String(fields.applicationType || '').trim()
  const transportMode = String(fields.transportMode || '').trim()
  const shouldEstimate = /差旅|住宿|交通/.test(applicationType) || Boolean(transportMode)

  if (!shouldEstimate || !days || !location) {
    return {
      canCalculate: false,
      reason: '缺少地点或天数',
      payload: null
    }
  }

  return {
    canCalculate: true,
    reason: '',
    payload: {
      days,
      location,
      grade
    }
  }
}

export function applyApplicationPolicyEstimateResult(preview = {}, result = {}, currentUser = {}) {
  const fields = { ...(preview?.fields || {}) }
  const days = Number(result?.days) || parseApplicationDaysValue(fields.days) || 1
  const hotelRate = formatPolicyMoney(result?.hotel_rate)
  const hotelAmount = formatPolicyMoney(result?.hotel_amount)
  const allowanceRate = formatPolicyMoney(result?.total_allowance_rate)
  const allowanceAmount = formatPolicyMoney(result?.allowance_amount)
  const totalAmount = formatPolicyMoney(result?.total_amount)
  const matchedCity = String(result?.matched_city || fields.location || '').trim()
  const grade = String(result?.grade || fields.grade || resolveCurrentUserGrade(currentUser)).trim()

  return normalizeApplicationPreview({
    ...preview,
    fields: {
      ...fields,
      grade,
      lodgingDailyCap: formatDailyPolicyMoney(result?.hotel_rate),
      subsidyDailyCap: formatDailyPolicyMoney(result?.total_allowance_rate),
      transportPolicy: buildTransportPolicyText(fields.transportMode),
      policyEstimate: `住宿 ${hotelAmount}元 + 补贴 ${allowanceAmount}元 = ${totalAmount}元（${days}天，不含交通票据）`,
      matchedCity,
      ruleName: String(result?.rule_name || '').trim(),
      ruleVersion: String(result?.rule_version || '').trim(),
      hotelAmount: hotelAmount ? `${hotelAmount}元` : '',
      allowanceAmount: allowanceAmount ? `${allowanceAmount}元` : '',
      policyTotalAmount: totalAmount ? `${totalAmount}元` : ''
    },
    policyEstimate: {
      ...result,
      grade,
      matchedCity
    },
    policyEstimateStatus: 'completed'
  })
}

export function applyApplicationPolicyEstimateError(preview = {}, error = null, currentUser = {}) {
  const fields = { ...(preview?.fields || {}) }
  const message = String(error?.message || error || '').trim()
  return normalizeApplicationPreview({
    ...preview,
    fields: {
      ...fields,
      grade: fields.grade || resolveCurrentUserGrade(currentUser),
      transportPolicy: buildTransportPolicyText(fields.transportMode),
      policyEstimate: message ? `规则中心暂未完成测算：${message}` : APPLICATION_POLICY_PENDING_TEXT
    },
    policyEstimateStatus: message ? 'failed' : 'pending'
  })
}

export function shouldUseLocalApplicationPreview(rawText, options = {}) {
  if (String(options.sessionType || '').trim() !== APPLICATION_SESSION_TYPE) return false
  if (options.systemGenerated || options.reviewAction || Number(options.attachmentCount || 0) > 0) return false

  const compact = compactText(rawText)
  if (!compact || APPLICATION_QUERY_PATTERN.test(compact)) return false
  return APPLICATION_CREATE_PATTERN.test(compact)
}

export function normalizeApplicationPreview(preview = {}) {
  const fields = ensureApplicationPolicyFields(preview?.fields || {})
  const missingFields = buildMissingFields(fields)
  return {
    ...preview,
    fields,
    missingFields,
    readyToSubmit: missingFields.length === 0
  }
}

export function buildModelRefinedApplicationPreview(localPreview = {}, ontology = {}, rawText = '', currentUser = {}) {
  const currentFields = localPreview?.fields || {}
  const ontologyFields = buildApplicationFieldsFromOntology(ontology || {}, rawText, currentUser)
  const parseStrategy = String(ontology?.parse_strategy || '').trim()
  const refinedFields = {
    ...currentFields,
    applicationType: normalizeApplicationTypeLabel(
      ontologyFields.expenseTypeLabel,
      currentFields.applicationType
    ),
    time: resolveProvidedValue(ontologyFields.timeRange, currentFields.time),
    location: resolveProvidedValue(ontologyFields.location, currentFields.location),
    reason: resolveProvidedValue(ontologyFields.reason, currentFields.reason),
    days: resolveProvidedValue(ontologyFields.days, currentFields.days),
    transportMode: normalizeTransportModeOption(
      ontologyFields.transportMode,
      currentFields.transportMode
    ),
    amount: normalizeAmountFromOntology(ontologyFields, currentFields.amount),
    grade: resolveProvidedValue(currentFields.grade, resolveCurrentUserGrade(currentUser)),
    applicant: resolveProvidedValue(ontologyFields.applicant, currentFields.applicant),
    department: resolveProvidedValue(ontologyFields.department, currentFields.department)
  }

  return normalizeApplicationPreview({
    ...localPreview,
    sourceText: String(rawText || localPreview.sourceText || '').trim(),
    fields: refinedFields,
    modelRefined: true,
    parseStrategy,
    modelReviewStatus: parseStrategy === 'llm_primary' ? 'completed' : 'fallback'
  })
}

export function buildApplicationPreviewRows(preview = {}) {
  const normalized = normalizeApplicationPreview(preview)
  const fields = normalized.fields || {}
  return APPLICATION_PREVIEW_FIELD_DEFINITIONS.map((item) => {
    const rawValue = fields[item.key]
    const value = String(rawValue || '').trim() || '待补充'
    return {
      ...item,
      value,
      editable: item.editable !== false,
      highlight: Boolean(item.highlight),
      missing: item.required !== false && !isApplicationPreviewValueProvided(rawValue)
    }
  })
}

export function buildApplicationPreviewSubmitText(preview = {}) {
  const rows = buildApplicationPreviewRows(preview)
  return [
    '费用申请确认提交',
    ...rows.map((row) => `${row.label}：${row.value}`),
    '',
    '确认提交'
  ].join('\n')
}

export function buildLocalApplicationPreview(rawText, currentUser = {}) {
  const sourceText = String(rawText || '').trim()
  const explicitDays = resolveApplicationDays(sourceText)
  const time = resolveApplicationTime(sourceText, explicitDays)
  const days = explicitDays || resolveDaysFromDateRange(time)
  const location = resolveApplicationLocation(sourceText)
  const fields = {
    applicationType: resolveApplicationType(sourceText),
    time,
    location,
    reason: resolveApplicationReason(sourceText, { location }),
    days,
    transportMode: resolveApplicationTransportMode(sourceText),
    amount: resolveApplicationAmount(sourceText),
    grade: resolveCurrentUserGrade(currentUser),
    applicant: currentUser.name || currentUser.username || '当前用户',
    department: currentUser.department || currentUser.departmentName || '待补充'
  }

  return normalizeApplicationPreview({
    sourceText,
    fields,
    modelReviewStatus: 'local'
  })
}

export function buildApplicationTemplatePreview(currentUser = {}) {
  return normalizeApplicationPreview({
    sourceText: '快速发起申请',
    fields: {
      applicationType: '费用申请',
      time: '',
      location: '',
      reason: '',
      days: '',
      transportMode: '',
      amount: '',
      grade: resolveCurrentUserGrade(currentUser),
      applicant: currentUser.name || currentUser.username || '当前用户',
      department: currentUser.department || currentUser.departmentName || '待补充'
    },
    modelReviewStatus: 'template'
  })
}

export function buildLocalApplicationPreviewMessage(preview) {
  const normalized = normalizeApplicationPreview(preview)
  const modelReviewStatus = String(normalized.modelReviewStatus || '').trim()
  return [
    modelReviewStatus === 'completed'
      ? '我已完成模型复核，并整理成下方表格。请核查识别结果；点击对应行即可直接编辑。'
      : modelReviewStatus === 'fallback'
        ? '模型复核没有返回稳定结果，我已先按规则兜底整理成下方表格。请重点核查识别结果；点击对应行即可直接编辑。'
        : modelReviewStatus === 'failed'
          ? '模型复核暂时失败，我先保留一份临时核对表，方便您核查和补充信息。点击对应行即可直接编辑。'
          : modelReviewStatus === 'template'
            ? '我已为你准备好费用申请模板。本步骤不调用大模型，也不会保存草稿；请点击对应行直接填写。'
            : '我先整理出下方表格，请核查识别结果。点击对应行即可直接编辑。'
  ].join('\n')
}

export function buildApplicationPreviewFooterMessage(preview) {
  const normalized = normalizeApplicationPreview(preview)
  const missingFields = Array.isArray(normalized.missingFields) ? normalized.missingFields : []
  if (missingFields.length) {
    return `当前还需要补充：${missingFields.join('、')}。补齐后我再帮您提交申请。`
  }

  return '请确认上述的信息是否填写正确？如果准确无误，点击 [确认](#application-submit) 进入审批环节。'
}
