import { addNumbers, roundTo } from '@/lib/decimal'
import { getBenchmarkBudgetSplitByScale, getScaleBudgetFeeSplit, type ScaleFeeSplitResult } from '@/lib/pricingScaleFee'

export type ScaleMode = 'cost' | 'area'

export interface ScaleBudgetCheckRow {
  benchmarkBudgetBasicChecked?: boolean
  benchmarkBudgetOptionalChecked?: boolean
}

export interface ScaleBudgetSourceRow extends ScaleBudgetCheckRow {
  amount?: number | null
  landArea?: number | null
  majorFactor?: number | null
  consultCategoryFactor?: number | null
  workStageFactor?: number | null
  workRatio?: number | null
}

export interface ScaleDetailComputedRow extends ScaleBudgetSourceRow {
  benchmarkBudget?: number | null
  benchmarkBudgetBasic?: number | null
  benchmarkBudgetOptional?: number | null
  basicFormula?: string | null
  optionalFormula?: string | null
  budgetFee?: number | null
  budgetFeeBasic?: number | null
  budgetFeeOptional?: number | null
}

export type CheckedScaleFeeSplitResult = Omit<ScaleFeeSplitResult, 'total'> & {
  total: number | null
}

const getScaleValueByMode = (
  row: Pick<ScaleBudgetSourceRow, 'amount' | 'landArea'> | undefined,
  mode: ScaleMode
) => (mode === 'cost' ? row?.amount : row?.landArea)

export const isSameNullableNumber = (left: number | null | undefined, right: number | null | undefined) => {
  if (left == null && right == null) return true
  if (left == null || right == null) return false
  return roundTo(left, 6) === roundTo(right, 6)
}

export const isSameNullableText = (left: string | null | undefined, right: string | null | undefined) =>
  String(left ?? '') === String(right ?? '')

export const isBenchmarkBudgetFullyUnchecked = (
  row?: Pick<ScaleBudgetCheckRow, 'benchmarkBudgetBasicChecked' | 'benchmarkBudgetOptionalChecked'>
) => row?.benchmarkBudgetBasicChecked === false && row?.benchmarkBudgetOptionalChecked === false

export const getBenchmarkBudgetRawSplitByRow = (
  row: Pick<ScaleBudgetSourceRow, 'amount' | 'landArea'> | undefined,
  mode: ScaleMode
) => getBenchmarkBudgetSplitByScale(getScaleValueByMode(row, mode), mode)

export const getCheckedBenchmarkBudgetSplitByRow = (
  row?: Pick<ScaleBudgetSourceRow, 'amount' | 'landArea' | 'benchmarkBudgetBasicChecked' | 'benchmarkBudgetOptionalChecked'>,
  mode: ScaleMode = 'cost'
): CheckedScaleFeeSplitResult | null => {
  const split = getBenchmarkBudgetRawSplitByRow(row, mode)
  if (!split) return null
  const basic = row?.benchmarkBudgetBasicChecked === false ? 0 : split.basic
  const optional = row?.benchmarkBudgetOptionalChecked === false ? 0 : split.optional
  return {
    ...split,
    basic,
    optional,
    total: isBenchmarkBudgetFullyUnchecked(row) ? null : roundTo(addNumbers(basic, optional), 2)
  }
}

export const getScaleBudgetFeeSplitByRow = (
  row?: Pick<
    ScaleBudgetSourceRow,
    | 'amount'
    | 'landArea'
    | 'benchmarkBudgetBasicChecked'
    | 'benchmarkBudgetOptionalChecked'
    | 'majorFactor'
    | 'consultCategoryFactor'
    | 'workStageFactor'
    | 'workRatio'
  >,
  mode: ScaleMode = 'cost'
) => {
  if (isBenchmarkBudgetFullyUnchecked(row)) return null
  const benchmarkBudgetSplit = getCheckedBenchmarkBudgetSplitByRow(row, mode)
  if (!benchmarkBudgetSplit) return null
  return getScaleBudgetFeeSplit({
    benchmarkBudgetBasic: benchmarkBudgetSplit.basic,
    benchmarkBudgetOptional: benchmarkBudgetSplit.optional,
    majorFactor: row?.majorFactor,
    consultCategoryFactor: row?.consultCategoryFactor,
    workStageFactor: row?.workStageFactor,
    workRatio: row?.workRatio
  })
}

export const getScaleBudgetFeeByRow = (
  row?: Pick<
    ScaleBudgetSourceRow,
    | 'amount'
    | 'landArea'
    | 'benchmarkBudgetBasicChecked'
    | 'benchmarkBudgetOptionalChecked'
    | 'majorFactor'
    | 'consultCategoryFactor'
    | 'workStageFactor'
    | 'workRatio'
  >,
  mode: ScaleMode = 'cost'
) => getScaleBudgetFeeSplitByRow(row, mode)?.total ?? null

export const recomputeScaleDetailRow = <TRow extends ScaleDetailComputedRow>(
  row: TRow,
  mode: ScaleMode
): TRow => {
  const benchmarkBudgetRawSplit = getBenchmarkBudgetRawSplitByRow(row, mode)
  const benchmarkBudgetSplit = getCheckedBenchmarkBudgetSplitByRow(row, mode)
  const budgetFeeSplit = getScaleBudgetFeeSplitByRow(row, mode)

  return {
    ...row,
    benchmarkBudget: benchmarkBudgetSplit?.total ?? null,
    benchmarkBudgetBasic: benchmarkBudgetSplit?.basic ?? null,
    benchmarkBudgetOptional: benchmarkBudgetSplit?.optional ?? null,
    basicFormula: row.benchmarkBudgetBasicChecked === false ? null : (benchmarkBudgetRawSplit?.basicFormula ?? ''),
    optionalFormula: row.benchmarkBudgetOptionalChecked === false ? null : (benchmarkBudgetRawSplit?.optionalFormula ?? ''),
    budgetFee: budgetFeeSplit?.total ?? null,
    budgetFeeBasic: budgetFeeSplit?.basic ?? null,
    budgetFeeOptional: budgetFeeSplit?.optional ?? null
  }
}

export const recomputeScaleDetailRowsInPlace = <TRow extends ScaleDetailComputedRow>(
  rows: TRow[],
  mode: ScaleMode
) => {
  for (const row of rows) {
    Object.assign(row, recomputeScaleDetailRow(row, mode))
  }
}

export const isSameScaleDetailRow = (
  left: ScaleDetailComputedRow,
  right: ScaleDetailComputedRow,
  mode: ScaleMode
) => {
  const isSameScaleValue = mode === 'cost'
    ? isSameNullableNumber(left.amount, right.amount)
    : isSameNullableNumber(left.landArea, right.landArea)

  return isSameScaleValue
    && isSameNullableNumber(left.benchmarkBudget, right.benchmarkBudget)
    && isSameNullableNumber(left.benchmarkBudgetBasic, right.benchmarkBudgetBasic)
    && isSameNullableNumber(left.benchmarkBudgetOptional, right.benchmarkBudgetOptional)
    && isSameNullableText(left.basicFormula, right.basicFormula)
    && isSameNullableText(left.optionalFormula, right.optionalFormula)
    && isSameNullableNumber(left.budgetFee, right.budgetFee)
    && isSameNullableNumber(left.budgetFeeBasic, right.budgetFeeBasic)
    && isSameNullableNumber(left.budgetFeeOptional, right.budgetFeeOptional)
}
