const {
  ATT_COEF,
  DEFAULT_DRIVER_PARAMS,
  SCALE_MAX,
  TWO_PI,
  getDriverParams,
  getSharedInputValues,
  toFiniteNumber
} = require('./calculation-context')
const {
  rawToTemperature,
  temperatureToRaw
} = require('./thermistor')

function getSpeedBase(inputValues = {}, driverParams = DEFAULT_DRIVER_PARAMS) {
  const candidates = [
    inputValues['速度基准'],
    getSharedInputValues()['速度基准'],
    driverParams.speedBase
  ]

  for (let index = 0; index < candidates.length; index += 1) {
    const speedBase = toFiniteNumber(candidates[index])

    if (speedBase > 0) return speedBase
  }

  return 0
}

function getSampleLimits(driverParams = getDriverParams()) {
  const baseVoltage = driverParams.baseVoltage
  const samplingResistorOhm = driverParams.samplingResistorMohm / 1000
  const currentSampleMax = baseVoltage / 2 / samplingResistorOhm / driverParams.opAmpGain
  const currentBase = currentSampleMax * 2
  const voltageSampleMax = driverParams.busVoltageDividerRatio * baseVoltage

  return {
    analogInputDividerRatio: driverParams.analogInputDividerRatio,
    baseVoltage,
    busVoltageDividerRatio: driverParams.busVoltageDividerRatio,
    carrierFrequencyKHz: driverParams.carrierFrequencyKHz,
    currentBase,
    currentSampleMax,
    speedBase: getSpeedBase({}, driverParams),
    voltageSampleMax
  }
}

function formatWriteValue(value) {
  if (!Number.isFinite(value)) return '--'
  return String(Math.round(value))
}

function formatFixedValue(value, precision = 2) {
  const numberValue = toFiniteNumber(value, NaN)
  if (!Number.isFinite(numberValue)) return '--'

  const text = numberValue.toFixed(precision)
  return Number(text) === 0 ? (0).toFixed(precision) : text
}

function calculateSpeedSlope(inputValues, driverParams = getDriverParams()) {
  const speedMin = toFiniteNumber(inputValues['速度最小值'])
  const speedMax = toFiniteNumber(inputValues['速度最大值'])
  const speedBase = getSpeedBase(inputValues, driverParams)
  const minVoltage = toFiniteNumber(inputValues['调速最低电压'])
  const maxVoltage = toFiniteNumber(inputValues['调速最高电压'])
  const { baseVoltage, analogInputDividerRatio } = getSampleLimits(driverParams)

  if (speedMax <= speedMin || maxVoltage <= minVoltage || !speedBase) return null

  return (speedMax - speedMin) / speedBase / ((maxVoltage - minVoltage) * analogInputDividerRatio / baseVoltage)
}

function calculateSpeedCommandWriteValue(actualValue, inputValues = {}, driverParams = getDriverParams()) {
  if (actualValue === '' || actualValue === undefined || actualValue === null) return '--'

  const numberValue = toFiniteNumber(actualValue, NaN)
  const speedBase = getSpeedBase(inputValues, driverParams)

  if (!Number.isFinite(numberValue) || !speedBase) return '--'

  return formatWriteValue(numberValue / speedBase * SCALE_MAX)
}

function calculateAtoGainWriteValues(atoBandwidth, inputValues = {}, driverParams = getDriverParams()) {
  if (atoBandwidth === '' || atoBandwidth === undefined || atoBandwidth === null) {
    return {
      kpWriteValue: '--',
      kiWriteValue: '--'
    }
  }

  const bandwidth = toFiniteNumber(atoBandwidth, NaN)
  const speedBase = getSpeedBase(inputValues, driverParams)
  const polePairs = toFiniteNumber(inputValues['极对数'])
  const sampleFrequency = driverParams.carrierFrequencyKHz * 1000
  const tpwmValue = 1 / sampleFrequency
  const baseFrequency = speedBase / 60 * polePairs

  if (!Number.isFinite(bandwidth) || !speedBase || !polePairs || !baseFrequency) {
    return {
      kpWriteValue: '--',
      kiWriteValue: '--'
    }
  }

  return {
    kpWriteValue: formatWriteValue(4095 * TWO_PI * ATT_COEF * bandwidth / baseFrequency),
    kiWriteValue: formatWriteValue(SCALE_MAX * TWO_PI * bandwidth * bandwidth * tpwmValue / baseFrequency)
  }
}

function calculateDqGainWriteValue(item, actualValue) {
  if (actualValue === '' || actualValue === undefined || actualValue === null) return '--'

  const numberValue = toFiniteNumber(actualValue, NaN)
  if (!Number.isFinite(numberValue)) return '--'

  if (item.gainType === 'kp') return formatWriteValue(4095 * numberValue)
  if (item.gainType === 'ki') return formatWriteValue(SCALE_MAX * numberValue)

  return formatWriteValue(numberValue)
}

function getFloatPrecision(item) {
  if (item.name === 'LD' || item.name === 'LQ') return 6
  if (item.name === 'RS') return 4

  return 2
}

function calculateParameterInputWriteValue(item, actualValue, inputValues = {}, driverParams = getDriverParams()) {
  if (actualValue === '' || actualValue === undefined || actualValue === null) return '--'

  const numberValue = toFiniteNumber(actualValue, NaN)
  if (!Number.isFinite(numberValue)) return '--'

  const { baseVoltage, analogInputDividerRatio } = getSampleLimits(driverParams)
  const speedBase = getSpeedBase(inputValues, driverParams)

  if (['开机电压', '关机电压', '调速最低电压', '调速最高电压'].includes(item.name)) {
    return formatWriteValue(SCALE_MAX * numberValue / baseVoltage * analogInputDividerRatio)
  }

  if (['速度最小值', '速度最大值'].includes(item.name)) {
    if (!speedBase) return '--'

    return formatWriteValue(SCALE_MAX * numberValue / speedBase)
  }

  if (item.name === 'SOUT_MAX') {
    const { currentBase } = getSampleLimits(driverParams)

    return formatWriteValue(numberValue / currentBase * SCALE_MAX)
  }

  if (item.name === '上油转速') {
    if (!speedBase) return '--'

    return formatWriteValue(SCALE_MAX * numberValue / speedBase)
  }

  if (item.type === 'uint8_t') {
    if (numberValue < 0 || numberValue > 0xFF) return '--'

    return formatWriteValue(numberValue)
  }

  if (item.type === 'float') return formatFixedValue(numberValue, getFloatPrecision(item))

  return formatWriteValue(numberValue)
}

function calculateProtectionWriteValue(item, actualValue, driverParams = getDriverParams()) {
  if (!actualValue && actualValue !== 0) return '--'

  const { currentBase, currentSampleMax, voltageSampleMax, speedBase } = getSampleLimits(driverParams)

  if (['过压保护值', '欠压保护值', '过压恢复值', '欠压恢复值'].includes(item.name)) {
    return formatWriteValue(actualValue / voltageSampleMax * SCALE_MAX)
  }

  if (item.name === '软件过流值') {
    return formatWriteValue(actualValue / currentBase * SCALE_MAX)
  }

  if (['速度限制最大值', '速度限制最小值', '速度中间值'].includes(item.name)) {
    return formatWriteValue(actualValue / speedBase * SCALE_MAX)
  }

  if (item.name === '功率保护值') {
    return formatWriteValue(actualValue / currentSampleMax / voltageSampleMax * SCALE_MAX)
  }

  if (item.name === '温度保护值' || item.name === '温度恢复值') {
    const rawValue = temperatureToRaw(actualValue, SCALE_MAX)

    return rawValue === null ? '--' : formatWriteValue(rawValue)
  }

  return item.type === 'float' ? formatFixedValue(Number(actualValue), 2) : formatWriteValue(actualValue)
}

function calculateParameterReadValue(item, rawValue, inputValues = {}, driverParams = getDriverParams()) {
  const rawNumber = toFiniteNumber(rawValue, NaN)
  if (!Number.isFinite(rawNumber)) return null

  const ratio = rawNumber / SCALE_MAX
  const {
    analogInputDividerRatio,
    baseVoltage,
    currentBase,
    currentSampleMax,
    voltageSampleMax
  } = getSampleLimits(driverParams)
  const speedBase = getSpeedBase(inputValues, driverParams)

  if (['开机电压', '关机电压', '调速最低电压', '调速最高电压'].includes(item.name)) {
    return analogInputDividerRatio ? ratio * baseVoltage / analogInputDividerRatio : null
  }

  if (['过压保护值', '欠压保护值', '过压恢复值', '欠压恢复值'].includes(item.name)) {
    return ratio * voltageSampleMax
  }

  if (['速度最小值', '速度最大值', '上油转速', '速度限制最大值', '速度限制最小值', '速度中间值'].includes(item.name)) {
    return speedBase ? ratio * speedBase : null
  }

  if (item.name === '软件过流值' || item.name === 'SOUT_MAX') {
    return ratio * currentBase
  }

  if (item.name === '功率保护值') {
    return ratio * currentSampleMax * voltageSampleMax
  }

  if (item.name === '温度保护值' || item.name === '温度恢复值') {
    return rawToTemperature(rawNumber, SCALE_MAX)
  }

  return null
}

function calculateStatusValue(name, rawValue, driverParams = getDriverParams()) {
  const rawNumber = toFiniteNumber(rawValue)
  const ratio = rawNumber / SCALE_MAX
  const {
    analogInputDividerRatio,
    baseVoltage,
    busVoltageDividerRatio,
    currentBase,
    currentSampleMax,
    voltageSampleMax,
    speedBase
  } = getSampleLimits(driverParams)

  if (name === '母线电压') return ratio * baseVoltage * busVoltageDividerRatio
  if (name === '母线电流') return ratio * currentBase
  if (name === 'NTC 温度') return rawToTemperature(rawNumber, SCALE_MAX)
  if (name === '模拟输入电压') return analogInputDividerRatio ? ratio * baseVoltage / analogInputDividerRatio : 0
  if (name === '估算速度') return ratio * speedBase
  if (name === '估算功率') return ratio * voltageSampleMax * currentSampleMax
  if (name === '频率' || name === '占空比') return rawNumber / 10
  return rawNumber
}

module.exports = {
  SCALE_MAX,
  calculateAtoGainWriteValues,
  calculateDqGainWriteValue,
  calculateParameterInputWriteValue,
  calculateParameterReadValue,
  calculateProtectionWriteValue,
  calculateSpeedCommandWriteValue,
  calculateSpeedSlope,
  calculateStatusValue,
  formatFixedValue
}
