import { getBasicFeeFromScale } from '@/sql'
import { addNumbers, roundTo, toDecimal, toFiniteNumberOrNull } from '@/lib/decimal'

type ScaleMode = 'cost' | 'area'

export interface ScaleFeeSplitResult {
  basic: number
  optional: number
  total: number
  basicFormula: string
  optionalFormula: string
}

/**
 * 根据“规模值 + 规模类型”查表，得到基准预算拆分结果。
 *
 * 这个方法只负责“规模法基准预算”这一层：
 * 1. 按投资规模或用地规模命中费率表
 * 2. 返回基准预算的基本部分 / 附加部分 / 合计
 * 3. 同时返回对应的计算式文本，供页面展示
 *
 * 它不参与任何咨询分类系数、专业系数、阶段系数的计算。
 */
export const getBenchmarkBudgetSplitByScale = (
  value: unknown,
  mode: ScaleMode
): ScaleFeeSplitResult | null => {
  const scaleValue = toFiniteNumberOrNull(value)

  const result = getBasicFeeFromScale(scaleValue, mode)

  if (!result) return null

  const basic = roundTo(result.basic, 2)
  const optional = roundTo(result.optional, 2)
  const basicFormula = typeof result.basicFormula === 'string' ? result.basicFormula : ''
  const optionalFormula = typeof result.optionalFormula === 'string' ? result.optionalFormula : ''
  return {
    basic,
    optional,
    total: roundTo(addNumbers(basic, optional), 2),
    basicFormula,
    optionalFormula
  }
}

export const getBenchmarkBudgetByScale = (value: unknown, mode: ScaleMode) => {
  const splitResult = getBenchmarkBudgetSplitByScale(value, mode)
  return splitResult ? splitResult.total : null
}

/**
 * 根据“已算出的基准预算拆分 + 各类系数”计算最终服务预算。
 *
 * 这个方法负责“乘系数”这一层：
 * 1. 输入的是已经拆好的基准预算 basic / optional
 * 2. 再乘咨询分类系数、专业系数、阶段系数、工作占比
 * 3. 返回服务费的基本部分 / 附加部分 / 合计
 *
 * 和 `getBenchmarkBudgetSplitByScale` 的区别是：
 * - `getBenchmarkBudgetSplitByScale` 解决“规模值对应多少基准预算”
 * - `getScaleBudgetFeeSplit` 解决“基准预算乘完系数后服务费是多少”
 *
 * 这里不返回计算式文本，所以 `basicFormula / optionalFormula` 固定为空字符串。
 */
export const getScaleBudgetFeeSplit = (params: {
  benchmarkBudgetBasic: unknown
  benchmarkBudgetOptional: unknown
  majorFactor: unknown
  consultCategoryFactor: unknown
  workStageFactor?: unknown
  workRatio?: unknown
}): ScaleFeeSplitResult | null => {
  const hasWorkStageFactor = Object.prototype.hasOwnProperty.call(params, 'workStageFactor')
  const hasWorkRatio = Object.prototype.hasOwnProperty.call(params, 'workRatio')
  const benchmarkBudgetBasic = toFiniteNumberOrNull(params.benchmarkBudgetBasic)
  const benchmarkBudgetOptional = toFiniteNumberOrNull(params.benchmarkBudgetOptional)
  const majorFactor = toFiniteNumberOrNull(params.majorFactor)
  const consultCategoryFactor = toFiniteNumberOrNull(params.consultCategoryFactor)
  const workStageFactor = hasWorkStageFactor ? toFiniteNumberOrNull(params.workStageFactor) : 1
  const workRatio = hasWorkRatio ? toFiniteNumberOrNull(params.workRatio) : 100

  if (
    benchmarkBudgetBasic == null ||
    benchmarkBudgetOptional == null ||
    majorFactor == null ||
    consultCategoryFactor == null ||
    workStageFactor == null ||
    workRatio == null
  ) {
    return null
  }

  const multiplier = toDecimal(consultCategoryFactor)
    .mul(majorFactor)
    .mul(workStageFactor)
    .mul(workRatio)
    .div(100)
  const roundedBenchmarkBudget = roundTo(addNumbers(benchmarkBudgetBasic, benchmarkBudgetOptional), 2)
  const basic = roundTo(toDecimal(benchmarkBudgetBasic).mul(multiplier), 2)
  const optional = roundTo(toDecimal(benchmarkBudgetOptional).mul(multiplier), 2)
  return {
    basic,
    optional,
    total: roundTo(toDecimal(roundedBenchmarkBudget).mul(multiplier), 2),
    basicFormula: '',
    optionalFormula: ''
  }
}

export const getScaleBudgetFee = (params: {
  benchmarkBudget: unknown
  majorFactor: unknown
  consultCategoryFactor: unknown
  workStageFactor?: unknown
  workRatio?: unknown
}) => {
  const hasWorkStageFactor = Object.prototype.hasOwnProperty.call(params, 'workStageFactor')
  const hasWorkRatio = Object.prototype.hasOwnProperty.call(params, 'workRatio')
  const benchmarkBudget = toFiniteNumberOrNull(params.benchmarkBudget)
  const majorFactor = toFiniteNumberOrNull(params.majorFactor)
  const consultCategoryFactor = toFiniteNumberOrNull(params.consultCategoryFactor)
  const workStageFactor = hasWorkStageFactor ? toFiniteNumberOrNull(params.workStageFactor) : 1
  const workRatio = hasWorkRatio ? toFiniteNumberOrNull(params.workRatio) : 100

  if (
    benchmarkBudget == null ||
    majorFactor == null ||
    consultCategoryFactor == null ||
    workStageFactor == null ||
    workRatio == null
  ) {
    return null
  }

  const roundedBenchmarkBudget = roundTo(benchmarkBudget, 2)
  const multiplier = toDecimal(consultCategoryFactor)
    .mul(majorFactor)
    .mul(workStageFactor)
    .mul(workRatio)
    .div(100)
  return roundTo(toDecimal(roundedBenchmarkBudget).mul(multiplier), 2)
}
