text: import {isNil, eq, gt, gte, lt, lte} from 'lodash'
  import {Errors} from './errors'
  import {isEmptyValue} from './utils'
  
  export const isInteger = ({value, getter}) => {
    if (isEmptyValue(value)) return null
    const numberValue = getter(value)
    return !Number.isInteger(numberValue) ? Errors.isInteger : null
  }
  
  export const isPositive = ({value, getter}) => {
    if (isEmptyValue(value)) return null
    const num = getter(value)
    return num < 0 ? Errors.isPositive : null
  }
  
  export const isNegative = ({value, getter}) => {
    if (isEmptyValue(value)) return null
    const num = getter(value)
    return num >= 0 ? Errors.isNegative : null
  }
  
  const compareWithOtherField = (value, otherFieldName, otherFieldLabel, siblings, getter, op, errorCode) => {
    if (isEmptyValue(value)) return null
    let err = null
    const val = getter(value)
    const otherVal = getter(siblings[otherFieldName])
  
    if (Number.isNaN(val) || Number.isNaN(otherVal)) return null
  
    err = op(val, otherVal) ? null : {
      error: errorCode,
      params: {
        value,
        otherFieldValue: otherVal,
        otherFieldLabel
      }
    }
  
    return err
  }
  
  const compareToThreshold = (value, op, threshold, getter, errorCode) => {
    if (isEmptyValue(value)) return null
    let err = null
    threshold = getter(threshold)
    value = getter(value)
    if (!isNaN(value) && !op(value, threshold)) {
      err = {
        error: errorCode,
        params: {value, threshold}
      }
    }
    return err
  }
  
  export const isGte = (threshold) => {
    return ({value, getter}) => {
      return compareToThreshold(value, gte, threshold, getter, Errors.isGte)
    }
  }
  
  export const isGt = (threshold) => {
    return ({value, getter}) => {
      return compareToThreshold(value, gt, threshold, getter, Errors.isGt)
    }
  }
  
  export const isLte = (threshold) => {
    return ({value, getter}) => {
      return compareToThreshold(value, lte, threshold, getter, Errors.isLte)
    }
  }
  
  export const isLt = (threshold) => {
    return ({value, getter}) => {
      return compareToThreshold(value, lt, threshold, getter, Errors.isLt)
    }
  }
  
  export const isEqualToField = (fieldName, fieldLabel) => {
    return ({value, siblings, getter}) => {
      return compareWithOtherField(value, fieldName, fieldLabel, siblings, getter, eq, Errors.isEqualToField)
    }
  }
  
  export const isGteToField = (fieldName, fieldLabel) => {
    return ({value, siblings, getter}) => {
      return compareWithOtherField(value, fieldName, fieldLabel, siblings, getter, gte, Errors.isGteToField)
    }
  }
  
  export const isGtField = (fieldName, fieldLabel) => {
    return ({value, siblings, getter}) => {
      return compareWithOtherField(value, fieldName, fieldLabel, siblings, getter, gt, Errors.isGtField)
    }
  }
  
  export const isLteToField = (fieldName, fieldLabel) => {
    return ({value, siblings, getter}) => {
      return compareWithOtherField(value, fieldName, fieldLabel, siblings, getter, lte, Errors.isLteToField)
    }
  }
  
  export const isLtField = (fieldName, fieldLabel) => {
    return ({value, siblings, getter}) => {
      return compareWithOtherField(value, fieldName, fieldLabel, siblings, getter, lt, Errors.isLtField)
    }
  }
  
  const ensureRangeParamsAreValid = (minValue, maxValue) => {
    if (isNil(minValue) || isNil(maxValue)) {
      throw new Error('minValue and maxValue cannot be null')
    } else if (minValue > maxValue) {
      throw new Error('minValue > maxValue')
    } else if (typeof minValue !== typeof maxValue) {
      throw new Error('range value must be of the same type')
    }
  }
  export const withinRange = (minValue, maxValue) => {
    ensureRangeParamsAreValid(minValue, maxValue)
  
    return ({value, getter}) => {
      if (isEmptyValue(value)) return null
      const getteredValue = getter(value)
      if (getteredValue < minValue || getteredValue > maxValue) {
        return {
          error: Errors.withinRange,
          params: {value, minValue, maxValue}
        }
      }
      return null
    }
  }
  