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

const TWO_PI = 2 * Math.PI

const MODE_OPTIONS = [
  { key: 'capacitive', label: '容抗' },
  { key: 'inductive', label: '感抗' }
]

const REACTANCE_UNIT_OPTIONS = [
  { label: 'mΩ', factor: 1e-3 },
  { label: 'Ω', factor: 1 },
  { label: 'kΩ', factor: 1e3 },
  { label: 'MΩ', factor: 1e6 },
  { label: 'GΩ', factor: 1e9 }
]

const ADMITTANCE_UNIT_OPTIONS = [
  { label: 'pS', factor: 1e-12 },
  { label: 'nS', factor: 1e-9 },
  { label: 'μS', factor: 1e-6 },
  { label: 'mS', factor: 1e-3 },
  { label: 'S', factor: 1 },
  { label: 'kS', factor: 1e3 },
  { label: 'MS', factor: 1e6 }
]

const CAPACITANCE_UNIT_OPTIONS = [
  { label: 'pF', factor: 1e-12 },
  { label: 'nF', factor: 1e-9 },
  { label: 'μF', factor: 1e-6 },
  { label: 'mF', factor: 1e-3 },
  { label: 'F', factor: 1 }
]

const INDUCTANCE_UNIT_OPTIONS = [
  { label: 'pH', factor: 1e-12 },
  { label: 'nH', factor: 1e-9 },
  { label: 'μH', factor: 1e-6 },
  { label: 'mH', factor: 1e-3 },
  { label: 'H', factor: 1 },
  { label: 'kH', factor: 1e3 }
]

const FREQUENCY_UNIT_OPTIONS = [
  { label: 'Hz', factor: 1 },
  { label: 'kHz', factor: 1e3 },
  { label: 'MHz', factor: 1e6 },
  { label: 'GHz', factor: 1e9 },
  { label: 'THz', factor: 1e12 }
]

function getReactiveUnitOptions(modeKey) {
  return modeKey === 'inductive' ? INDUCTANCE_UNIT_OPTIONS : CAPACITANCE_UNIT_OPTIONS
}

function formatUnitValue(baseValue, options, fallbackIndex = 0) {
  if (!Number.isFinite(baseValue)) return '--'

  const selected = selectBestUnit(options, baseValue, fallbackIndex)
  return formatScaledValue(baseValue, selected.unit, {
    fallbackText: '',
    includeUnit: true
  })
}

function createEmptyResultRows(modeKey) {
  const isInductive = modeKey === 'inductive'

  return [
    {
      label: isInductive ? '感抗 XL' : '容抗 XC',
      meta: isInductive ? 'XL = 2πfL' : 'XC = 1 / (2πfC)',
      value: '--'
    },
    {
      label: isInductive ? '感抗导纳 YL' : '容抗导纳 YC',
      meta: 'Y = 1 / X',
      value: '--'
    }
  ]
}

function calculateResultRows(modeKey, frequency, reactive) {
  const rows = createEmptyResultRows(modeKey)
  if (!Number.isFinite(frequency) || !Number.isFinite(reactive)) return rows

  const reactance = modeKey === 'inductive'
    ? TWO_PI * frequency * reactive
    : 1 / (TWO_PI * frequency * reactive)
  const admittance = 1 / reactance

  return [
    {
      ...rows[0],
      value: formatUnitValue(reactance, REACTANCE_UNIT_OPTIONS, 1)
    },
    {
      ...rows[1],
      value: formatUnitValue(admittance, ADMITTANCE_UNIT_OPTIONS, 4)
    }
  ]
}

function buildState(source = {}) {
  const modeIndex = normalizeIndex(source.reactanceModeIndex, MODE_OPTIONS, 0)
  const mode = getOption(MODE_OPTIONS, modeIndex)
  const reactiveUnitOptions = getReactiveUnitOptions(mode.key)
  const capacitanceUnitIndex = normalizeIndex(source.reactanceCapacitanceUnitIndex, CAPACITANCE_UNIT_OPTIONS, 1)
  const frequencyUnitIndex = normalizeIndex(source.reactanceFrequencyUnitIndex, FREQUENCY_UNIT_OPTIONS, 0)
  const inductanceUnitIndex = normalizeIndex(source.reactanceInductanceUnitIndex, INDUCTANCE_UNIT_OPTIONS, 3)
  const reactiveUnitIndex = mode.key === 'inductive' ? inductanceUnitIndex : capacitanceUnitIndex
  const frequencyUnit = getOption(FREQUENCY_UNIT_OPTIONS, frequencyUnitIndex)
  const reactiveUnit = getOption(reactiveUnitOptions, reactiveUnitIndex)
  const frequencyText = String(source.reactanceFrequencyValue || '')
  const reactiveText = String(source.reactanceReactiveValue || '')
  const frequencyNumber = parsePositiveNumber(frequencyText)
  const reactiveNumber = parsePositiveNumber(reactiveText)
  const invalidInput = [frequencyNumber, reactiveNumber].some((value) => Number.isNaN(value))
  const values = {
    frequency: Number.isFinite(frequencyNumber) ? frequencyNumber * frequencyUnit.factor : null,
    reactive: Number.isFinite(reactiveNumber) ? reactiveNumber * reactiveUnit.factor : null
  }
  let frequencyDisplayUnit = frequencyUnit
  let frequencyDisplayUnitIndex = frequencyUnitIndex
  let reactiveDisplayUnit = reactiveUnit
  let reactiveDisplayUnitIndex = reactiveUnitIndex

  let frequencyDisplayValue = Number.isFinite(frequencyNumber)
    ? formatMagnitudeNumber(frequencyNumber, { fallbackText: '' })
    : frequencyText
  let reactiveDisplayValue = Number.isFinite(reactiveNumber)
    ? formatMagnitudeNumber(reactiveNumber, { fallbackText: '' })
    : reactiveText

  const resultRows = invalidInput
    ? createEmptyResultRows(mode.key)
    : calculateResultRows(mode.key, values.frequency, values.reactive)

  return {
    reactanceCapacitanceUnitIndex: mode.key === 'capacitive' ? reactiveDisplayUnitIndex : capacitanceUnitIndex,
    reactanceErrorText: invalidInput ? '输入值需大于 0' : '',
    reactanceFrequencyDisplayValue: frequencyDisplayValue,
    reactanceFrequencyUnitIndex: frequencyDisplayUnitIndex,
    reactanceFrequencyUnitOptions: FREQUENCY_UNIT_OPTIONS,
    reactanceFrequencyUnitText: frequencyDisplayUnit.label,
    reactanceFrequencyValue: frequencyText,
    reactanceInductanceUnitIndex: mode.key === 'inductive' ? reactiveDisplayUnitIndex : inductanceUnitIndex,
    reactanceModeIndex: modeIndex,
    reactanceModeKey: mode.key,
    reactanceModeOptions: MODE_OPTIONS,
    reactanceModeText: mode.label,
    reactanceReactiveDisplayValue: reactiveDisplayValue,
    reactanceReactiveName: mode.key === 'inductive' ? '电感' : '电容',
    reactanceReactiveSymbol: mode.key === 'inductive' ? 'L' : 'C',
    reactanceReactiveUnitIndex: reactiveDisplayUnitIndex,
    reactanceReactiveUnitOptions: reactiveUnitOptions,
    reactanceReactiveUnitText: reactiveDisplayUnit.label,
    reactanceReactiveValue: reactiveText,
    reactanceResultRows: resultRows
  }
}

function createInitialState() {
  return buildState({
    reactanceCapacitanceUnitIndex: 1,
    reactanceFrequencyUnitIndex: 0,
    reactanceInductanceUnitIndex: 3,
    reactanceModeIndex: 0,
    reactanceReactiveValue: ''
  })
}

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

function clearInputs(state = {}) {
  return updateState(state, {
    reactanceFrequencyValue: '',
    reactanceReactiveValue: ''
  })
}

function normalizeValue(state, fieldKey, fieldValue) {
  const source = buildState(state)
  const config = {
    frequency: {
      options: FREQUENCY_UNIT_OPTIONS,
      unitIndex: source.reactanceFrequencyUnitIndex,
      unitIndexKey: 'reactanceFrequencyUnitIndex',
      valueKey: 'reactanceFrequencyValue'
    },
    reactive: {
      options: source.reactanceReactiveUnitOptions,
      unitIndex: source.reactanceReactiveUnitIndex,
      unitIndexKey: source.reactanceModeKey === 'inductive'
        ? 'reactanceInductanceUnitIndex'
        : 'reactanceCapacitanceUnitIndex',
      valueKey: 'reactanceReactiveValue'
    }
  }[fieldKey]

  if (!config) return source

  const text = fieldValue === undefined ? source[config.valueKey] : fieldValue
  const numberValue = parsePositiveNumber(text)
  if (!Number.isFinite(numberValue)) {
    return updateState(source, {
      [config.valueKey]: text
    })
  }

  const currentUnit = getOption(config.options, config.unitIndex)
  const baseValue = numberValue * currentUnit.factor
  const selected = selectBestUnit(config.options, baseValue, config.unitIndex)

  return updateState(source, {
    [config.unitIndexKey]: selected.index,
    [config.valueKey]: formatScaledValue(baseValue, selected.unit, { fallbackText: '' })
  })
}

module.exports = {
  ADMITTANCE_UNIT_OPTIONS,
  CAPACITANCE_UNIT_OPTIONS,
  FREQUENCY_UNIT_OPTIONS,
  INDUCTANCE_UNIT_OPTIONS,
  MODE_OPTIONS,
  REACTANCE_UNIT_OPTIONS,
  clearInputs,
  createInitialState,
  normalizeValue,
  updateState
}
