/**
 * 规模法通用计算（投资规模法 + 用地规模法共用）
 *
 * 提供行默认值构建、行合并、费用计算等纯函数，
 * 供 ScalePricingPane.vue 和 pricingMethodTotals.ts 共用。
 */

import { getMajorDictEntries, getMajorIdAliasMap, getServiceDictById } from '@/sql'
import { toFiniteNumberOrNull } from '@/lib/decimal'
import { getBenchmarkBudgetByScale, getScaleBudgetFee } from '@/lib/pricingScaleFee'
import type {
  ScaleCalcRow,
  ScaleType,
  MajorLite,
  ServiceLite
} from '@/types/pricing'

/* ----------------------------------------------------------------
 * 专业字典查询
 * ---------------------------------------------------------------- */

const majorById = new Map(
  getMajorDictEntries().map(({ id, item }) => [id, item as MajorLite])
)
const majorIdAliasMap = getMajorIdAliasMap()

/** 获取专业叶子节点 ID 列表（code 含 '-' 的为叶子） */
export const getMajorLeafIds = (): string[] =>
  getMajorDictEntries()
    .filter(({ item }) => Boolean(item?.code && String(item.code).includes('-')))
    .map(({ id }) => id)

/** 解析专业 ID 别名 */
export const resolveMajorId = (id: string): string =>
  majorById.has(id) ? id : majorIdAliasMap.get(id) || id

/** 获取专业默认系数 */
export const getDefaultMajorFactor = (id: string): number | null => {
  const resolvedId = resolveMajorId(id)
  return toFiniteNumberOrNull(majorById.get(resolvedId)?.defCoe)
}

/** 判断专业是否支持投资规模（hasCost） */
export const isCostMajor = (id: string): boolean => {
  const resolvedId = resolveMajorId(id)
  return majorById.get(resolvedId)?.hasCost !== false
}

/** 判断专业是否支持用地规模（hasArea） */
export const isAreaMajor = (id: string): boolean => {
  const resolvedId = resolveMajorId(id)
  return majorById.get(resolvedId)?.hasArea !== false
}

/** 判断专业是否同时支持投资和用地 */
export const isDualScaleMajor = (id: string): boolean =>
  isCostMajor(id) && isAreaMajor(id)

/** 根据行业 ID 查找对应的专业条目 */
export const getIndustryMajorEntry = (industryId: string | null | undefined) => {
  const key = String(industryId || '').trim()
  if (!key) return null
  for (const [id, item] of majorById.entries()) {
    const majorIndustryId = String(item?.industryId ?? '').trim()
    if (majorIndustryId === key && !String(item?.code || '').includes('-')) {
      return { id, item }
    }
  }
  return null
}

/* ----------------------------------------------------------------
 * 咨询服务字典查询
 * ---------------------------------------------------------------- */

/** 获取咨询服务默认分类系数 */
export const getDefaultConsultCategoryFactor = (serviceId: string | number): number | null => {
  const service = (getServiceDictById() as Record<string, ServiceLite | undefined>)[String(serviceId)]
  return toFiniteNumberOrNull(service?.defCoe)
}

/** 判断是否为仅投资规模服务 */
export const isOnlyCostScaleService = (serviceId: string | number): boolean => {
  const service = (getServiceDictById() as Record<string, ServiceLite | undefined>)[String(serviceId)]
  return service?.onlyCostScale === true
}

/* ----------------------------------------------------------------
 * 行构建与合并
 * ---------------------------------------------------------------- */

/** 判断是否为分组汇总行（AG Grid tree 用） */
export const isGroupScaleRow = (row: unknown): boolean =>
  Boolean(row && typeof row === 'object' && (row as Record<string, unknown>).isGroupRow === true)

/** 过滤掉分组汇总行 */
export const stripGroupScaleRows = <TRow>(rows: TRow[] | undefined): TRow[] =>
  (rows || []).filter(row => !isGroupScaleRow(row))

/** 构建规模法默认行（全部专业叶子） */
export const buildDefaultScaleRows = (
  serviceId: string | number,
  consultCategoryFactorMap?: Map<string, number | null>,
  majorFactorMap?: Map<string, number | null>
): ScaleCalcRow[] => {
  const defaultFactor =
    consultCategoryFactorMap?.get(String(serviceId)) ?? getDefaultConsultCategoryFactor(serviceId)
  return getMajorLeafIds().map(id => ({
    id,
    amount: null,
    landArea: null,
    consultCategoryFactor: defaultFactor,
    majorFactor: majorFactorMap?.get(id) ?? getDefaultMajorFactor(id),
    workStageFactor: 1,
    workRatio: 100
  }))
}

const hasOwn = (obj: unknown, key: string) =>
  Object.prototype.hasOwnProperty.call(obj || {}, key)

const toRowMap = <TRow extends { id: string }>(rows?: TRow[]) => {
  const map = new Map<string, TRow>()
  for (const row of rows || []) map.set(String(row.id), row)
  return map
}

/** 合并持久化行与默认行（保留用户编辑值，补全缺失字段） */
export const mergeScaleRows = (
  serviceId: string | number,
  rowsFromDb: Array<Partial<ScaleCalcRow> & Pick<ScaleCalcRow, 'id'>> | undefined,
  consultCategoryFactorMap?: Map<string, number | null>,
  majorFactorMap?: Map<string, number | null>
): ScaleCalcRow[] => {
  const sourceRows = stripGroupScaleRows(rowsFromDb)
  const dbValueMap = toRowMap(sourceRows)
  // 处理 ID 别名映射
  for (const row of sourceRows) {
    const nextId = majorIdAliasMap.get(String(row.id))
    if (nextId && !dbValueMap.has(nextId)) {
      dbValueMap.set(nextId, row as ScaleCalcRow)
    }
  }

  const defaultFactor =
    consultCategoryFactorMap?.get(String(serviceId)) ?? getDefaultConsultCategoryFactor(serviceId)

  return buildDefaultScaleRows(serviceId, consultCategoryFactorMap, majorFactorMap).map(row => {
    const fromDb = dbValueMap.get(row.id)
    if (!fromDb) return row
    return {
      ...row,
      amount: toFiniteNumberOrNull(fromDb.amount),
      landArea: toFiniteNumberOrNull(fromDb.landArea),
      consultCategoryFactor:
        toFiniteNumberOrNull(fromDb.consultCategoryFactor) ??
        (hasOwn(fromDb, 'consultCategoryFactor') ? null : defaultFactor),
      majorFactor:
        toFiniteNumberOrNull(fromDb.majorFactor) ??
        (hasOwn(fromDb, 'majorFactor') ? null : (majorFactorMap?.get(row.id) ?? getDefaultMajorFactor(row.id))),
      workStageFactor:
        toFiniteNumberOrNull(fromDb.workStageFactor) ??
        (hasOwn(fromDb, 'workStageFactor') ? null : row.workStageFactor),
      workRatio:
        toFiniteNumberOrNull(fromDb.workRatio) ??
        (hasOwn(fromDb, 'workRatio') ? null : row.workRatio)
    }
  })
}

/* ----------------------------------------------------------------
 * 费用计算
 * ---------------------------------------------------------------- */

/** 计算投资规模法单行费用 */
export const calcInvestBudgetFee = (row: ScaleCalcRow): number | null =>
  getScaleBudgetFee({
    benchmarkBudget: getBenchmarkBudgetByScale(row.amount, 'cost'),
    majorFactor: row.majorFactor,
    consultCategoryFactor: row.consultCategoryFactor,
    workStageFactor: row.workStageFactor,
    workRatio: row.workRatio
  })

/** 计算用地规模法单行费用 */
export const calcLandBudgetFee = (row: ScaleCalcRow): number | null =>
  getScaleBudgetFee({
    benchmarkBudget: getBenchmarkBudgetByScale(row.landArea, 'area'),
    majorFactor: row.majorFactor,
    consultCategoryFactor: row.consultCategoryFactor,
    workStageFactor: row.workStageFactor,
    workRatio: row.workRatio
  })

/** 根据规模类型计算单行费用 */
export const calcScaleBudgetFee = (row: ScaleCalcRow, scaleType: ScaleType): number | null =>
  scaleType === 'invest' ? calcInvestBudgetFee(row) : calcLandBudgetFee(row)

/** 判断行是否属于指定规模类型 */
export const isRowForScaleType = (rowId: string, scaleType: ScaleType): boolean =>
  scaleType === 'invest' ? isCostMajor(rowId) : isAreaMajor(rowId)

/* ----------------------------------------------------------------
 * 可空数值求和
 * ---------------------------------------------------------------- */

/** 对数组求和，全部为 null 时返回 null */
export const sumNullableBy = <T>(list: T[], pick: (item: T) => number | null | undefined): number | null => {
  let hasValid = false
  let total = 0
  for (const item of list) {
    const value = toFiniteNumberOrNull(pick(item))
    if (value == null) continue
    hasValid = true
    total += value
  }
  return hasValid ? total : null
}
