text: import KEYS from '../../constants/keys';
  import getDelta from './delta';
  
  export default function createExtremumModel(layoutService, viewStateOptions = {}) {
    function resolveExtrema(scaleName) {
      // Choose between data min/max and explicit min/max. Explicit values have higher priority
      const measurePath = scaleName === KEYS.SCALE.X ? 'qMeasureInfo.0' : 'qMeasureInfo.1';
      const measureIndex = scaleName === KEYS.SCALE.X ? 0 : 1;
      let minFromLayout = layoutService.getHyperCubeValue(`${measurePath}.qMin`, 0);
      let maxFromLayout = layoutService.getHyperCubeValue(`${measurePath}.qMax`, 1);
      let explicitType = 'none';
  
      const axis = scaleName === KEYS.SCALE.X ? 'xAxis' : 'yAxis';
      const { autoMinMax, minMax, min, max } = layoutService.getLayoutValue(axis);
      if (!autoMinMax) {
        explicitType = minMax;
        switch (minMax) {
          case 'min':
            minFromLayout = min;
            maxFromLayout = Math.max(minFromLayout, maxFromLayout);
            break;
          case 'max':
            maxFromLayout = max;
            minFromLayout = Math.min(minFromLayout, maxFromLayout);
            break;
          default:
            minFromLayout = Math.min(min, max);
            maxFromLayout = Math.max(min, max);
            break;
        }
      }
  
      const source = layoutService.meta.isSnapshot
        ? layoutService.getLayoutValue('snapshotData.content.chartData', {})
        : viewStateOptions;
      let axisMin = typeof source[`${axis}Min`] === 'number' ? source[`${axis}Min`] : minFromLayout;
      let axisMax = typeof source[`${axis}Max`] === 'number' ? source[`${axis}Max`] : maxFromLayout;
  
      if (typeof source[`${axis}Min`] === 'number' && typeof source[`${axis}Max`] === 'number') explicitType = 'minMax';
      else if (typeof source[`${axis}Min`] === 'number') {
        // Updating explicit type: merging the new explicit info. with the old one.
        switch (explicitType) {
          case 'max':
          case 'minMax':
            explicitType = 'minMax';
            break;
          default:
            explicitType = 'min';
            break;
        }
      } else if (typeof source[`${axis}Max`] === 'number') {
        switch (explicitType) {
          case 'min':
          case 'minMax':
            explicitType = 'minMax';
            break;
          default:
            explicitType = 'max';
            break;
        }
      }
  
      // Add 5% padding to the ends that are not explicit.
      let padding = (axisMax - axisMin) / 20;
      // Special case: padding === 0 because data has only one point and min/max are non-explicit
      if (padding === 0) padding = Math.abs(axisMin) > 0 ? Math.abs(axisMin) / 10 : 10;
      switch (explicitType) {
        case 'minMax':
          if (axisMin === axisMax) {
            padding = getDelta({ layoutService, value: axisMin, measureIndex });
            axisMin -= padding;
            axisMax += padding;
          }
          break;
        case 'min':
          axisMax += padding;
          break;
        case 'max':
          axisMin -= padding;
          break;
        case 'none':
          axisMin -= padding;
          axisMax += padding;
          break;
        default:
          break;
      }
  
      return {
        [`${axis}Min`]: axisMin,
        [`${axis}Max`]: axisMax,
        [`${axis}ExplicitType`]: explicitType,
      };
    }
  
    let xExtrema = resolveExtrema(KEYS.SCALE.X);
    let yExtrema = resolveExtrema(KEYS.SCALE.Y);
  
    const model = {
      query: {
        getXExtrema: () => xExtrema,
        getYExtrema: () => yExtrema,
      },
      command: {
        updateExtrema: (dataView, isHomeState) => {
          const { xAxisMin, xAxisMax, yAxisMin, yAxisMax } = dataView;
          xExtrema.xAxisMin = xAxisMin;
          xExtrema.xAxisMax = xAxisMax;
          yExtrema.yAxisMin = yAxisMin;
          yExtrema.yAxisMax = yAxisMax;
          if (!isHomeState) {
            xExtrema.xAxisExplicitType = 'minMax';
            yExtrema.yAxisExplicitType = 'minMax';
          }
        },
        resetExtrema: () => {
          xExtrema = resolveExtrema(KEYS.SCALE.X);
          yExtrema = resolveExtrema(KEYS.SCALE.Y);
        },
      },
    };
  
    return model;
  }
  