const {
  formatMagnitudeNumber,
  getOption,
  normalizeIndex,
  parseLooseNumber,
  selectBestUnit
} = require('../calculator-helpers.js')

const MODE_OPTIONS = [
  { key: 'water', label: '水侧冷量' },
  { key: 'airSensible', label: '风侧显热' },
  { key: 'airEnthalpy', label: '风侧焓差' },
  { key: 'cop', label: 'COP' },
  { key: 'carnot', label: '卡诺COP' },
  { key: 'temperature', label: '过热过冷' }
]

const FIELD_GROUPS = {
  airEnthalpy: [
    { key: 'coolingAirFlow', label: '风量', unit: 'm³/h', placeholder: '3000' },
    { key: 'coolingAirInletEnthalpy', label: '入口焓值', unit: 'kJ/kg', placeholder: '58' },
    { key: 'coolingAirOutletEnthalpy', label: '出口焓值', unit: 'kJ/kg', placeholder: '42' }
  ],
  airSensible: [
    { key: 'coolingAirFlow', label: '风量', unit: 'm³/h', placeholder: '3000' },
    { key: 'coolingAirInletTemp', label: '入口温度', unit: '°C', placeholder: '27' },
    { key: 'coolingAirOutletTemp', label: '出口温度', unit: '°C', placeholder: '15' }
  ],
  carnot: [
    { key: 'coolingEvapTemp', label: '蒸发温度', unit: '°C', placeholder: '0' },
    { key: 'coolingCondTemp', label: '冷凝温度', unit: '°C', placeholder: '40' }
  ],
  cop: [
    { key: 'coolingCapacity', label: '制冷量', unit: 'kW', placeholder: '10' },
    { key: 'coolingInputPower', label: '输入功率', unit: 'kW', placeholder: '2.5' }
  ],
  temperature: [
    { key: 'coolingSuctionTemp', label: '吸气温度', unit: '°C', placeholder: '8' },
    { key: 'coolingEvapTemp', label: '蒸发饱和温度', unit: '°C', placeholder: '2' },
    { key: 'coolingCondTemp', label: '冷凝饱和温度', unit: '°C', placeholder: '45' },
    { key: 'coolingLiquidTemp', label: '液管温度', unit: '°C', placeholder: '39' }
  ],
  water: [
    { key: 'coolingWaterFlow', label: '水流量', unit: 'm³/h', placeholder: '10' },
    { key: 'coolingWaterInlet', label: '入口温度', unit: '°C', placeholder: '12' },
    { key: 'coolingWaterOutlet', label: '出口温度', unit: '°C', placeholder: '7' }
  ]
}

const FORMULA_TEXT = {
  airEnthalpy: 'Q = 风量 × Δh / 3000',
  airSensible: 'Q = 0.000335 × 风量 × ΔT',
  carnot: 'COP = Te(K) / (Tc(K) - Te(K))',
  cop: 'COP = 制冷量 / 输入功率',
  temperature: '过热度 = 吸气 - 蒸发饱和，过冷度 = 冷凝饱和 - 液管',
  water: 'Q = 1.163 × 水流量 × ΔT'
}

const POWER_UNITS = [
  { label: 'W', factor: 0.001 },
  { label: 'kW', factor: 1 },
  { label: 'MW', factor: 1000 }
]
const COOLING_FORMAT_STEPS = [
  { min: 1000, decimals: 2 },
  { min: 1, decimals: 3 },
  { min: 0.001, decimals: 5 },
  { min: 0, decimals: 8 }
]

const COOLING_VALUE_KEYS = [
  'coolingAirFlow',
  'coolingAirInletEnthalpy',
  'coolingAirInletTemp',
  'coolingAirOutletEnthalpy',
  'coolingAirOutletTemp',
  'coolingCapacity',
  'coolingCondTemp',
  'coolingEvapTemp',
  'coolingInputPower',
  'coolingLiquidTemp',
  'coolingSuctionTemp',
  'coolingWaterFlow',
  'coolingWaterInlet',
  'coolingWaterOutlet'
]

function formatNumber(value) {
  return formatMagnitudeNumber(value, {
    fallbackText: '--',
    steps: COOLING_FORMAT_STEPS
  })
}

function formatPower(kwValue) {
  const unit = selectBestUnit(POWER_UNITS, kwValue, 1).unit

  return `${formatNumber(kwValue / unit.factor)} ${unit.label}`
}

function makeRow(label, value, unit = '') {
  return {
    label,
    value: unit ? `${formatNumber(value)} ${unit}` : formatNumber(value)
  }
}

function hasAll(values, keys) {
  return keys.every((key) => Number.isFinite(values[key]))
}

function calculate(modeKey, values) {
  if (Object.keys(values).some((key) => Number.isNaN(values[key]))) {
    return {
      errorText: '输入值格式无效',
      resultRows: []
    }
  }

  if (modeKey === 'water') {
    if (!hasAll(values, ['coolingWaterFlow', 'coolingWaterInlet', 'coolingWaterOutlet'])) return { errorText: '', resultRows: [] }
    if (values.coolingWaterFlow < 0) return { errorText: '流量不能为负数', resultRows: [] }

    const deltaT = Math.abs(values.coolingWaterInlet - values.coolingWaterOutlet)
    const capacityKw = 1.163 * values.coolingWaterFlow * deltaT

    return {
      errorText: '',
      resultRows: [
        { label: '冷量', value: formatPower(capacityKw) },
        makeRow('温差', deltaT, '°C'),
        makeRow('冷吨', capacityKw / 3.517, 'RT')
      ]
    }
  }

  if (modeKey === 'airSensible') {
    if (!hasAll(values, ['coolingAirFlow', 'coolingAirInletTemp', 'coolingAirOutletTemp'])) return { errorText: '', resultRows: [] }
    if (values.coolingAirFlow < 0) return { errorText: '风量不能为负数', resultRows: [] }

    const deltaT = Math.abs(values.coolingAirInletTemp - values.coolingAirOutletTemp)
    const capacityKw = 0.000335 * values.coolingAirFlow * deltaT

    return {
      errorText: '',
      resultRows: [
        { label: '显热冷量', value: formatPower(capacityKw) },
        makeRow('温差', deltaT, '°C'),
        makeRow('冷吨', capacityKw / 3.517, 'RT')
      ]
    }
  }

  if (modeKey === 'airEnthalpy') {
    if (!hasAll(values, ['coolingAirFlow', 'coolingAirInletEnthalpy', 'coolingAirOutletEnthalpy'])) return { errorText: '', resultRows: [] }
    if (values.coolingAirFlow < 0) return { errorText: '风量不能为负数', resultRows: [] }

    const deltaH = Math.abs(values.coolingAirInletEnthalpy - values.coolingAirOutletEnthalpy)
    const capacityKw = values.coolingAirFlow * deltaH / 3000

    return {
      errorText: '',
      resultRows: [
        { label: '总冷量', value: formatPower(capacityKw) },
        makeRow('焓差', deltaH, 'kJ/kg'),
        makeRow('冷吨', capacityKw / 3.517, 'RT')
      ]
    }
  }

  if (modeKey === 'cop') {
    if (!hasAll(values, ['coolingCapacity', 'coolingInputPower'])) return { errorText: '', resultRows: [] }
    if (values.coolingCapacity < 0 || values.coolingInputPower <= 0) return { errorText: '制冷量需大于等于0，输入功率需大于0', resultRows: [] }

    const cop = values.coolingCapacity / values.coolingInputPower

    return {
      errorText: '',
      resultRows: [
        makeRow('COP', cop),
        makeRow('EER', cop * 3.412),
        { label: '制冷量', value: formatPower(values.coolingCapacity) }
      ]
    }
  }

  if (modeKey === 'carnot') {
    if (!hasAll(values, ['coolingEvapTemp', 'coolingCondTemp'])) return { errorText: '', resultRows: [] }

    const evapK = values.coolingEvapTemp + 273.15
    const condK = values.coolingCondTemp + 273.15
    if (evapK <= 0 || condK <= evapK) return { errorText: '冷凝温度需高于蒸发温度，且绝对温度需大于0K', resultRows: [] }

    const coolingCop = evapK / (condK - evapK)
    const heatingCop = condK / (condK - evapK)

    return {
      errorText: '',
      resultRows: [
        makeRow('制冷COP', coolingCop),
        makeRow('制热COP', heatingCop),
        makeRow('温差', values.coolingCondTemp - values.coolingEvapTemp, '°C')
      ]
    }
  }

  if (modeKey === 'temperature') {
    if (!hasAll(values, ['coolingSuctionTemp', 'coolingEvapTemp', 'coolingCondTemp', 'coolingLiquidTemp'])) return { errorText: '', resultRows: [] }

    return {
      errorText: '',
      resultRows: [
        makeRow('过热度', values.coolingSuctionTemp - values.coolingEvapTemp, '°C'),
        makeRow('过冷度', values.coolingCondTemp - values.coolingLiquidTemp, '°C')
      ]
    }
  }

  return {
    errorText: '',
    resultRows: []
  }
}

function buildState(source = {}) {
  const modeIndex = normalizeIndex(source.coolingModeIndex, MODE_OPTIONS, 0)
  const mode = getOption(MODE_OPTIONS, modeIndex)
  const rawValues = COOLING_VALUE_KEYS.reduce((result, key) => {
    result[key] = String(source[key] === undefined || source[key] === null ? '' : source[key])
    return result
  }, {})
  const values = COOLING_VALUE_KEYS.reduce((result, key) => {
    result[key] = parseLooseNumber(rawValues[key])
    return result
  }, {})
  const result = calculate(mode.key, values)
  const fieldRows = (FIELD_GROUPS[mode.key] || []).map((field) => ({
    ...field,
    value: rawValues[field.key]
  }))

  return {
    ...rawValues,
    coolingAnyInput: COOLING_VALUE_KEYS.some((key) => rawValues[key].trim()),
    coolingErrorText: result.errorText,
    coolingFieldRows: fieldRows,
    coolingFormulaText: FORMULA_TEXT[mode.key] || '',
    coolingModeIndex: modeIndex,
    coolingModeKey: mode.key,
    coolingModeOptions: MODE_OPTIONS,
    coolingModeText: mode.label,
    coolingResultRows: result.resultRows
  }
}

function createInitialState() {
  return buildState({})
}

function updateState(state, changedData = {}) {
  return buildState({
    ...state,
    ...changedData
  })
}

function clearInputs(state) {
  const changedData = COOLING_VALUE_KEYS.reduce((result, key) => {
    result[key] = ''
    return result
  }, {})

  return updateState(state, changedData)
}

module.exports = {
  MODE_OPTIONS,
  clearInputs,
  createInitialState,
  updateState
}
