import { useState, useRef } from 'react'
import { Input, InputNumber } from 'antd'
import PropTypes from 'prop-types'
import FunctionIcon from '../../Icons/FunctionIcon'

const OPERATOR_KEYS = ['+', '-', '*', '/']

/**
 * Safely evaluate a math expression. Only allows numbers and +, -, *, /
 */
function safeEval(expr) {
  const sanitized = String(expr)
    .replace(/\s/g, '')
    .replace(/[^0-9+\-*/().]/g, '')
  if (!sanitized) return null
  try {
    const fn = new Function(`return (${sanitized})`)
    const result = fn()
    return typeof result === 'number' && Number.isFinite(result) ? result : null
  } catch {
    return null
  }
}

const InputNumberCal = ({
  value,
  onChange,
  onBlur,
  min,
  max,
  prefix,
  suffix,
  placeholder,
  disabled,
  ...rest
}) => {
  const [isExprMode, setIsExprMode] = useState(false)
  const [exprValue, setExprValue] = useState('')
  const inputRef = useRef(null)

  const switchToExprMode = (initialValue) => {
    setIsExprMode(true)
    setExprValue(initialValue)
    setTimeout(() => {
      //inputRef.current?.focus()
      const input = inputRef.current.getElementsByTagName('input')[0]
      if (input) {
        input.focus()
      }
    }, 0)
  }

  const exitExprMode = (result) => {
    setIsExprMode(false)
    setExprValue('')
    if (result != null) {
      const clamped =
        min != null && result < min
          ? min
          : max != null && result > max
            ? max
            : result
      onChange?.(clamped)
    }
  }

  const handleNumberKeyDown = (e) => {
    if (OPERATOR_KEYS.includes(e.key)) {
      e.preventDefault()
      const current = value ?? ''
      switchToExprMode(String(current) + e.key)
    }
  }

  const handleInputChange = (e) => {
    const next = e.target.value
    setExprValue(next)
    const num = parseFloat(next)
    if (next === '') {
      onChange?.(null)
    } else if (!next.match(/[+\-*/=]/) && !Number.isNaN(num)) {
      onChange?.(num)
    }
  }

  const handleInputKeyDown = (e) => {
    if (e.key === '=') {
      e.preventDefault()
      const result = safeEval(exprValue)
      if (result != null) {
        exitExprMode(result)
      }
    }
  }

  const handleInputBlur = (e) => {
    const expr = exprValue.trim()
    if (expr && expr.match(/[+\-*/]/)) {
      const result = safeEval(expr)
      if (result != null) {
        exitExprMode(result)
      } else {
        exitExprMode(null)
      }
    } else {
      const num = parseFloat(expr)
      if (!Number.isNaN(num)) {
        exitExprMode(num)
      } else {
        exitExprMode(null)
      }
    }
    onBlur?.(e)
  }

  const commonProps = {
    prefix,
    suffix,
    placeholder,
    disabled,
    min,
    max,
    ...rest
  }

  if (isExprMode) {
    return (
      <div className='input-number-cal' ref={inputRef}>
        <Input
          value={exprValue}
          onChange={handleInputChange}
          onKeyDown={handleInputKeyDown}
          onBlur={handleInputBlur}
          {...commonProps}
        />
        <div className='input-number-cal-icon'>
          <FunctionIcon style={{ fontSize: 24 }} />
        </div>
      </div>
    )
  }

  return (
    <InputNumber
      {...commonProps}
      value={value != null ? value : null}
      onChange={onChange}
      onBlur={onBlur}
      onKeyDown={handleNumberKeyDown}
    />
  )
}

InputNumberCal.propTypes = {
  value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
  onChange: PropTypes.func,
  onBlur: PropTypes.func,
  min: PropTypes.number,
  max: PropTypes.number,
  step: PropTypes.number,
  prefix: PropTypes.node,
  suffix: PropTypes.node,
  placeholder: PropTypes.string,
  disabled: PropTypes.bool
}

export default InputNumberCal
