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

const TWO_PI = 2 * Math.PI
const DIAGRAM_COMPONENT_SRC = {
  c: '/assets/filter-diagram/capacitor-h.svg',
  l: '/assets/filter-diagram/inductor-h.svg',
  r: '/assets/filter-diagram/resistor-h.svg'
}

const NETWORK_OPTIONS = [
  { key: 'rc', label: 'RC' },
  { key: 'rl', label: 'RL' }
]
const RESPONSE_OPTIONS = [
  { key: 'lowpass', label: '低通' },
  { key: 'highpass', label: '高通' }
]
const RESISTANCE_UNIT_OPTIONS = [
  { label: 'mΩ', factor: 1e-3 },
  { label: 'Ω', factor: 1 },
  { label: 'kΩ', factor: 1e3 },
  { label: 'MΩ', factor: 1e6 },
  { label: 'GΩ', factor: 1e9 }
]
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(networkKey) {
  return networkKey === 'rl' ? INDUCTANCE_UNIT_OPTIONS : CAPACITANCE_UNIT_OPTIONS
}

function getDiagramComponentSrc(componentKey) {
  return DIAGRAM_COMPONENT_SRC[componentKey] || DIAGRAM_COMPONENT_SRC.r
}

function getDiagramComponentLabel(componentKey) {
  return String(componentKey || '').toUpperCase()
}

function getDiagramComponents(networkKey, responseKey) {
  if (networkKey === 'rc' && responseKey === 'highpass') {
    return { series: 'c', shunt: 'r' }
  }
  if (networkKey === 'rl' && responseKey === 'lowpass') {
    return { series: 'l', shunt: 'r' }
  }
  if (networkKey === 'rl' && responseKey === 'highpass') {
    return { series: 'r', shunt: 'l' }
  }

  return { series: 'r', shunt: 'c' }
}

function calculateMissingValue(networkKey, values) {
  const hasResistance = Number.isFinite(values.resistance)
  const hasReactive = Number.isFinite(values.reactive)
  const hasFrequency = Number.isFinite(values.frequency)
  const validCount = [hasResistance, hasReactive, hasFrequency].filter(Boolean).length

  if (validCount < 2) {
    return {
      computedKey: '',
      errorText: ''
    }
  }

  if (validCount > 2) {
    return {
      computedKey: '',
      errorText: '保留两项，清空一项用于计算'
    }
  }

  if (networkKey === 'rl') {
    if (!hasResistance) {
      return {
        computedKey: 'resistance',
        value: TWO_PI * values.frequency * values.reactive
      }
    }
    if (!hasReactive) {
      return {
        computedKey: 'reactive',
        value: values.resistance / (TWO_PI * values.frequency)
      }
    }
    return {
      computedKey: 'frequency',
      value: values.resistance / (TWO_PI * values.reactive)
    }
  }

  if (!hasResistance) {
    return {
      computedKey: 'resistance',
      value: 1 / (TWO_PI * values.frequency * values.reactive)
    }
  }
  if (!hasReactive) {
    return {
      computedKey: 'reactive',
      value: 1 / (TWO_PI * values.frequency * values.resistance)
    }
  }
  return {
    computedKey: 'frequency',
    value: 1 / (TWO_PI * values.resistance * values.reactive)
  }
}

function buildState(source = {}) {
  const networkIndex = normalizeIndex(source.filterNetworkIndex, NETWORK_OPTIONS, 0)
  const responseIndex = normalizeIndex(source.filterResponseIndex, RESPONSE_OPTIONS, 0)
  const network = getOption(NETWORK_OPTIONS, networkIndex)
  const response = getOption(RESPONSE_OPTIONS, responseIndex)
  const reactiveUnitOptions = getReactiveUnitOptions(network.key)
  const resistanceUnitIndex = normalizeIndex(source.filterResistanceUnitIndex, RESISTANCE_UNIT_OPTIONS, 1)
  const capacitanceUnitIndex = normalizeIndex(source.filterCapacitanceUnitIndex, CAPACITANCE_UNIT_OPTIONS, 1)
  const inductanceUnitIndex = normalizeIndex(source.filterInductanceUnitIndex, INDUCTANCE_UNIT_OPTIONS, 3)
  const frequencyUnitIndex = normalizeIndex(source.filterFrequencyUnitIndex, FREQUENCY_UNIT_OPTIONS, 0)
  const reactiveUnitIndex = network.key === 'rl' ? inductanceUnitIndex : capacitanceUnitIndex
  const resistanceUnit = getOption(RESISTANCE_UNIT_OPTIONS, resistanceUnitIndex)
  const reactiveUnit = getOption(reactiveUnitOptions, reactiveUnitIndex)
  const frequencyUnit = getOption(FREQUENCY_UNIT_OPTIONS, frequencyUnitIndex)
  const resistanceText = String(source.filterResistanceValue || '')
  const reactiveText = String(source.filterReactiveValue || '')
  const frequencyText = String(source.filterFrequencyValue || '')
  const resistanceNumber = parsePositiveNumber(resistanceText)
  const reactiveNumber = parsePositiveNumber(reactiveText)
  const frequencyNumber = parsePositiveNumber(frequencyText)
  const invalidInput = [resistanceNumber, reactiveNumber, frequencyNumber].some((value) => Number.isNaN(value))
  const values = {
    frequency: Number.isFinite(frequencyNumber) ? frequencyNumber * frequencyUnit.factor : null,
    reactive: Number.isFinite(reactiveNumber) ? reactiveNumber * reactiveUnit.factor : null,
    resistance: Number.isFinite(resistanceNumber) ? resistanceNumber * resistanceUnit.factor : null
  }
  const calculated = invalidInput
    ? { computedKey: '', errorText: '输入值需大于 0' }
    : calculateMissingValue(network.key, values)
  const computedValue = Number.isFinite(calculated.value) ? calculated.value : null
  const diagram = getDiagramComponents(network.key, response.key)
  let resistanceDisplayUnit = resistanceUnit
  let resistanceDisplayUnitIndex = resistanceUnitIndex
  let reactiveDisplayUnit = reactiveUnit
  let reactiveDisplayUnitIndex = reactiveUnitIndex
  let frequencyDisplayUnit = frequencyUnit
  let frequencyDisplayUnitIndex = frequencyUnitIndex

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

  if (computedValue !== null && calculated.computedKey === 'resistance') {
    const selected = selectBestUnit(RESISTANCE_UNIT_OPTIONS, computedValue, resistanceUnitIndex)
    resistanceDisplayUnit = selected.unit
    resistanceDisplayUnitIndex = selected.index
    resistanceDisplayValue = formatScaledValue(computedValue, resistanceDisplayUnit, { fallbackText: '' })
  } else if (computedValue !== null && calculated.computedKey === 'reactive') {
    const selected = selectBestUnit(reactiveUnitOptions, computedValue, reactiveUnitIndex)
    reactiveDisplayUnit = selected.unit
    reactiveDisplayUnitIndex = selected.index
    reactiveDisplayValue = formatScaledValue(computedValue, reactiveDisplayUnit, { fallbackText: '' })
  } else if (computedValue !== null && calculated.computedKey === 'frequency') {
    const selected = selectBestUnit(FREQUENCY_UNIT_OPTIONS, computedValue, frequencyUnitIndex)
    frequencyDisplayUnit = selected.unit
    frequencyDisplayUnitIndex = selected.index
    frequencyDisplayValue = formatScaledValue(computedValue, frequencyDisplayUnit, { fallbackText: '' })
  }

  return {
    filterCapacitanceUnitIndex: network.key === 'rc' ? reactiveDisplayUnitIndex : capacitanceUnitIndex,
    filterComputedKey: calculated.computedKey || '',
    filterErrorText: calculated.errorText || '',
    filterFrequencyDisplayValue: frequencyDisplayValue,
    filterFrequencyUnitIndex: frequencyDisplayUnitIndex,
    filterFrequencyUnitOptions: FREQUENCY_UNIT_OPTIONS,
    filterFrequencyUnitText: frequencyDisplayUnit.label,
    filterFrequencyValue: frequencyText,
    filterFormulaText: network.key === 'rl' ? 'fc = R / (2πL)' : 'fc = 1 / (2πRC)',
    filterInductanceUnitIndex: network.key === 'rl' ? reactiveDisplayUnitIndex : inductanceUnitIndex,
    filterNetworkIndex: networkIndex,
    filterNetworkKey: network.key,
    filterNetworkOptions: NETWORK_OPTIONS,
    filterNetworkText: network.label,
    filterReactiveDisplayValue: reactiveDisplayValue,
    filterReactiveName: network.key === 'rl' ? '电感' : '电容',
    filterReactiveSymbol: network.key === 'rl' ? 'L' : 'C',
    filterReactiveUnitIndex: reactiveDisplayUnitIndex,
    filterReactiveUnitOptions: reactiveUnitOptions,
    filterReactiveUnitText: reactiveDisplayUnit.label,
    filterReactiveValue: reactiveText,
    filterResistanceDisplayValue: resistanceDisplayValue,
    filterResistanceUnitIndex: resistanceDisplayUnitIndex,
    filterResistanceUnitOptions: RESISTANCE_UNIT_OPTIONS,
    filterResistanceUnitText: resistanceDisplayUnit.label,
    filterResistanceValue: resistanceText,
    filterResponseIndex: responseIndex,
    filterResponseKey: response.key,
    filterResponseOptions: RESPONSE_OPTIONS,
    filterResponseText: response.label,
    filterSeriesLabel: getDiagramComponentLabel(diagram.series),
    filterSeriesComponentSrc: getDiagramComponentSrc(diagram.series),
    filterShuntLabel: getDiagramComponentLabel(diagram.shunt),
    filterShuntComponentSrc: getDiagramComponentSrc(diagram.shunt)
  }
}

function createInitialState() {
  return buildState({
    filterCapacitanceUnitIndex: 1,
    filterFrequencyUnitIndex: 0,
    filterInductanceUnitIndex: 3,
    filterNetworkIndex: 0,
    filterReactiveValue: '',
    filterResistanceUnitIndex: 1,
    filterResistanceValue: '',
    filterResponseIndex: 0
  })
}

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

function normalizeValue(state, fieldKey, fieldValue) {
  const source = buildState(state)
  const config = {
    frequency: {
      options: FREQUENCY_UNIT_OPTIONS,
      unitIndex: source.filterFrequencyUnitIndex,
      unitIndexKey: 'filterFrequencyUnitIndex',
      valueKey: 'filterFrequencyValue'
    },
    reactive: {
      options: source.filterReactiveUnitOptions,
      unitIndex: source.filterReactiveUnitIndex,
      unitIndexKey: source.filterNetworkKey === 'rl'
        ? 'filterInductanceUnitIndex'
        : 'filterCapacitanceUnitIndex',
      valueKey: 'filterReactiveValue'
    },
    resistance: {
      options: RESISTANCE_UNIT_OPTIONS,
      unitIndex: source.filterResistanceUnitIndex,
      unitIndexKey: 'filterResistanceUnitIndex',
      valueKey: 'filterResistanceValue'
    }
  }[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 = {
  CAPACITANCE_UNIT_OPTIONS,
  FREQUENCY_UNIT_OPTIONS,
  INDUCTANCE_UNIT_OPTIONS,
  NETWORK_OPTIONS,
  RESISTANCE_UNIT_OPTIONS,
  RESPONSE_OPTIONS,
  createInitialState,
  normalizeValue,
  updateState
}
