text: import Defaults from './Defaults'
  import Utils from './../../utils/Utils'
  import Options from './Options'
  
  /**
   * ApexCharts Config Class for extending user options with pre-defined ApexCharts config.
   *
   * @module Config
   **/
  export default class Config {
    constructor(opts) {
      this.opts = opts
    }
  
    init({ responsiveOverride }) {
      let opts = this.opts
      let options = new Options()
      let defaults = new Defaults(opts)
  
      this.chartType = opts.chart.type
  
      if (this.chartType === 'histogram') {
        // technically, a histogram can be drawn by a column chart with no spaces in between
        opts.chart.type = 'bar'
        opts = Utils.extend(
          {
            plotOptions: {
              bar: {
                columnWidth: '99.99%'
              }
            }
          },
          opts
        )
      }
  
      opts = this.extendYAxis(opts)
      opts = this.extendAnnotations(opts)
  
      let config = options.init()
      let newDefaults = {}
      if (opts && typeof opts === 'object') {
        let chartDefaults = {}
        const chartTypes = [
          'line',
          'area',
          'bar',
          'candlestick',
          'boxPlot',
          'rangeBar',
          'histogram',
          'bubble',
          'scatter',
          'heatmap',
          'treemap',
          'pie',
          'polarArea',
          'donut',
          'radar',
          'radialBar'
        ]
  
        if (chartTypes.indexOf(opts.chart.type) !== -1) {
          chartDefaults = defaults[opts.chart.type]()
        } else {
          chartDefaults = defaults.line()
        }
  
        if (opts.chart.brush && opts.chart.brush.enabled) {
          chartDefaults = defaults.brush(chartDefaults)
        }
  
        if (opts.chart.stacked && opts.chart.stackType === '100%') {
          opts = defaults.stacked100(opts)
        }
  
        // If user has specified a dark theme, make the tooltip dark too
        this.checkForDarkTheme(window.Apex) // check global window Apex options
        this.checkForDarkTheme(opts) // check locally passed options
  
        opts.xaxis = opts.xaxis || window.Apex.xaxis || {}
  
        // an important boolean needs to be set here
        // otherwise all the charts will have this flag set to true window.Apex.xaxis is set globally
        if (!responsiveOverride) {
          opts.xaxis.convertedCatToNumeric = false
        }
  
        opts = this.checkForCatToNumericXAxis(this.chartType, chartDefaults, opts)
  
        if (
          (opts.chart.sparkline && opts.chart.sparkline.enabled) ||
          (window.Apex.chart &&
            window.Apex.chart.sparkline &&
            window.Apex.chart.sparkline.enabled)
        ) {
          chartDefaults = defaults.sparkline(chartDefaults)
        }
        newDefaults = Utils.extend(config, chartDefaults)
      }
  
      // config should cascade in this fashion
      // default-config < global-apex-variable-config < user-defined-config
  
      // get GLOBALLY defined options and merge with the default config
      let mergedWithDefaultConfig = Utils.extend(newDefaults, window.Apex)
  
      // get the merged config and extend with user defined config
      config = Utils.extend(mergedWithDefaultConfig, opts)
  
      // some features are not supported. those mismatches should be handled
      config = this.handleUserInputErrors(config)
  
      return config
    }
  
    checkForCatToNumericXAxis(chartType, chartDefaults, opts) {
      let defaults = new Defaults(opts)
  
      const isBarHorizontal =
        (chartType === 'bar' || chartType === 'boxPlot') &&
        opts.plotOptions &&
        opts.plotOptions.bar &&
        opts.plotOptions.bar.horizontal
  
      const unsupportedZoom =
        chartType === 'pie' ||
        chartType === 'polarArea' ||
        chartType === 'donut' ||
        chartType === 'radar' ||
        chartType === 'radialBar' ||
        chartType === 'heatmap'
  
      const notNumericXAxis =
        opts.xaxis.type !== 'datetime' && opts.xaxis.type !== 'numeric'
  
      let tickPlacement = opts.xaxis.tickPlacement
        ? opts.xaxis.tickPlacement
        : chartDefaults.xaxis && chartDefaults.xaxis.tickPlacement
      if (
        !isBarHorizontal &&
        !unsupportedZoom &&
        notNumericXAxis &&
        tickPlacement !== 'between'
      ) {
        opts = defaults.convertCatToNumeric(opts)
      }
  
      return opts
    }
  
    extendYAxis(opts, w) {
      let options = new Options()
  
      if (
        typeof opts.yaxis === 'undefined' ||
        !opts.yaxis ||
        (Array.isArray(opts.yaxis) && opts.yaxis.length === 0)
      ) {
        opts.yaxis = {}
      }
  
      // extend global yaxis config (only if object is provided / not an array)
      if (
        opts.yaxis.constructor !== Array &&
        window.Apex.yaxis &&
        window.Apex.yaxis.constructor !== Array
      ) {
        opts.yaxis = Utils.extend(opts.yaxis, window.Apex.yaxis)
      }
  
      // as we can't extend nested object's array with extend, we need to do it first
      // user can provide either an array or object in yaxis config
      if (opts.yaxis.constructor !== Array) {
        // convert the yaxis to array if user supplied object
        opts.yaxis = [Utils.extend(options.yAxis, opts.yaxis)]
      } else {
        opts.yaxis = Utils.extendArray(opts.yaxis, options.yAxis)
      }
  
      let isLogY = false
      opts.yaxis.forEach((y) => {
        if (y.logarithmic) {
          isLogY = true
        }
      })
  
      let series = opts.series
      if (w && !series) {
        series = w.config.series
      }
  
      // Do something smart here when series length is > 1 and not equal to yaxis length and yaxis length > 1
      if (
        !isLogY &&
        series.length > 1 &&
        opts.yaxis.length > 1 &&
        series.length !== opts.yaxis.length
      ) {
        opts.yaxis = opts.yaxis.map((yaxisInfo, index) => {
          return yaxisInfo
        })
      }
  
      // A logarithmic chart works correctly when each series has a corresponding y-axis
      // If this is not the case, we manually create yaxis for multi-series log chart
      if (isLogY && series.length !== opts.yaxis.length && series.length) {
        opts.yaxis = series.map((s, i) => {
          if (!s.name) {
            series[i].name = `series-${i + 1}`
          }
  
          if (series.length !== opts.yaxis.length) {
            let totalYAxisPoints = 0
            opts.yaxis.forEach((element, index) => {
              if (Array.isArray(element.seriesName)) {
                totalYAxisPoints = totalYAxisPoints + element.seriesName.length
              } else {
                totalYAxisPoints = totalYAxisPoints + 1
              }
            })
  
            if (series.length === totalYAxisPoints) {
              let result = undefined
  
              opts.yaxis.forEach((element, index) => {
                if (Array.isArray(element.seriesName)) {
                  result = element.seriesName.includes(series[i].name)
                    ? element
                    : undefined
                } else {
                  result =
                    element.seriesName === series[i].name ? element : undefined
                }
              })
  
              if (result) {
                return result
              }
            }
          }
  
          if (opts.yaxis[i]) {
            opts.yaxis[i].seriesName = series[i].name
            return opts.yaxis[i]
          } else {
            const newYaxis = Utils.extend(options.yAxis, opts.yaxis[0])
            newYaxis.show = false
            return newYaxis
          }
        })
      }
  
      if (isLogY && series.length > 1 && series.length !== opts.yaxis.length) {
        console.warn(
          'A multi-series logarithmic chart should have equal number of series and y-axes. Please make sure to equalize both.'
        )
      }
      return opts
    }
  
    // annotations also accepts array, so we need to extend them manually
    extendAnnotations(opts) {
      if (typeof opts.annotations === 'undefined') {
        opts.annotations = {}
        opts.annotations.yaxis = []
        opts.annotations.xaxis = []
        opts.annotations.points = []
      }
  
      opts = this.extendYAxisAnnotations(opts)
      opts = this.extendXAxisAnnotations(opts)
      opts = this.extendPointAnnotations(opts)
  
      return opts
    }
  
    extendYAxisAnnotations(opts) {
      let options = new Options()
  
      opts.annotations.yaxis = Utils.extendArray(
        typeof opts.annotations.yaxis !== 'undefined'
          ? opts.annotations.yaxis
          : [],
        options.yAxisAnnotation
      )
      return opts
    }
  
    extendXAxisAnnotations(opts) {
      let options = new Options()
  
      opts.annotations.xaxis = Utils.extendArray(
        typeof opts.annotations.xaxis !== 'undefined'
          ? opts.annotations.xaxis
          : [],
        options.xAxisAnnotation
      )
      return opts
    }
    extendPointAnnotations(opts) {
      let options = new Options()
  
      opts.annotations.points = Utils.extendArray(
        typeof opts.annotations.points !== 'undefined'
          ? opts.annotations.points
          : [],
        options.pointAnnotation
      )
      return opts
    }
  
    checkForDarkTheme(opts) {
      if (opts.theme && opts.theme.mode === 'dark') {
        if (!opts.tooltip) {
          opts.tooltip = {}
        }
        if (opts.tooltip.theme !== 'light') {
          opts.tooltip.theme = 'dark'
        }
  
        if (!opts.chart.foreColor) {
          opts.chart.foreColor = '#f6f7f8'
        }
  
        if (!opts.chart.background) {
          opts.chart.background = '#424242'
        }
  
        if (!opts.theme.palette) {
          opts.theme.palette = 'palette4'
        }
      }
    }
  
    handleUserInputErrors(opts) {
      let config = opts
      // conflicting tooltip option. intersect makes sure to focus on 1 point at a time. Shared cannot be used along with it
      if (config.tooltip.shared && config.tooltip.intersect) {
        throw new Error(
          'tooltip.shared cannot be enabled when tooltip.intersect is true. Turn off any other option by setting it to false.'
        )
      }
  
      if (config.chart.type === 'bar' && config.plotOptions.bar.horizontal) {
        // No multiple yaxis for bars
        if (config.yaxis.length > 1) {
          throw new Error(
            'Multiple Y Axis for bars are not supported. Switch to column chart by setting plotOptions.bar.horizontal=false'
          )
        }
  
        // if yaxis is reversed in horizontal bar chart, you should draw the y-axis on right side
        if (config.yaxis[0].reversed) {
          config.yaxis[0].opposite = true
        }
  
        config.xaxis.tooltip.enabled = false // no xaxis tooltip for horizontal bar
        config.yaxis[0].tooltip.enabled = false // no xaxis tooltip for horizontal bar
        config.chart.zoom.enabled = false // no zooming for horz bars
      }
  
      if (config.chart.type === 'bar' || config.chart.type === 'rangeBar') {
        if (config.tooltip.shared) {
          if (
            config.xaxis.crosshairs.width === 'barWidth' &&
            config.series.length > 1
          ) {
            config.xaxis.crosshairs.width = 'tickWidth'
          }
        }
      }
  
      if (
        config.chart.type === 'candlestick' ||
        config.chart.type === 'boxPlot'
      ) {
        if (config.yaxis[0].reversed) {
          console.warn(
            `Reversed y-axis in ${config.chart.type} chart is not supported.`
          )
          config.yaxis[0].reversed = false
        }
      }
  
      // if user supplied array for stroke width, it will only be applicable to line/area charts, for any other charts, revert back to Number
      if (Array.isArray(config.stroke.width)) {
        if (config.chart.type !== 'line' && config.chart.type !== 'area') {
          console.warn(
            'stroke.width option accepts array only for line and area charts. Reverted back to Number'
          )
          config.stroke.width = config.stroke.width[0]
        }
      }
  
      return config
    }
  }
  