// @ts-check
import CoreUtils from '../../../modules/CoreUtils'
import Utils from '../../../utils/Utils'

export default class Helpers {
  /**
   * @param {import('../../../charts/Line').default} lineCtx
   */
  constructor(lineCtx) {
    this.w = lineCtx.w
    this.lineCtx = lineCtx
  }

  /**
   * @param {number} i
   * @param {any[]} series
   */
  sameValueSeriesFix(i, series) {
    const w = this.w

    if (
      w.config.fill.type === 'gradient' ||
      w.config.fill.type[i] === 'gradient'
    ) {
      const coreUtils = new CoreUtils(this.lineCtx.w)

      // applied only to LINE chart
      // a small adjustment to allow gradient line to draw correctly for all same values
      /* #fix https://github.com/apexcharts/apexcharts.js/issues/358 */
      if (coreUtils.seriesHaveSameValues(i)) {
        const gSeries = series[i].slice()
        gSeries[gSeries.length - 1] = gSeries[gSeries.length - 1] + 0.000001
        series[i] = gSeries
      }
    }
    return series
  }

  /** @param {{series: any, realIndex: any, x: any, y: any, i: any, j: any, prevY: any}} opts */
  calculatePoints({ series, realIndex, x, y, i, j, prevY }) {
    const w = this.w

    const ptX = []
    const ptY = []

    let xPT1st = this.lineCtx.categoryAxisCorrection + w.config.markers.offsetX

    // the first point for line series
    // we need to check whether it's not a time series, because a time series may
    // start from the middle of the x axis
    if (w.axisFlags.isXNumeric) {
      xPT1st =
        (w.seriesData.seriesX[realIndex][0] - w.globals.minX) /
          this.lineCtx.xRatio +
        w.config.markers.offsetX
    }

    // push 2 points for the first data values
    if (j === 0) {
      ptX.push(xPT1st)
      ptY.push(
        Utils.isNumber(series[i][0]) ? prevY + w.config.markers.offsetY : null,
      )
    }

    ptX.push(x + w.config.markers.offsetX)
    ptY.push(
      Utils.isNumber(series[i][j + 1]) ? y + w.config.markers.offsetY : null,
    )

    return {
      x: ptX,
      y: ptY,
    }
  }

  /** @param {{pathFromLine: any, pathFromArea: any, realIndex: any}} opts */
  checkPreviousPaths({ pathFromLine, pathFromArea, realIndex }) {
    const w = this.w

    for (let pp = 0; pp < w.globals.previousPaths.length; pp++) {
      const gpp = w.globals.previousPaths[pp]

      if (
        (gpp.type === 'line' || gpp.type === 'area') &&
        gpp.paths.length > 0 &&
        parseInt(gpp.realIndex, 10) === parseInt(realIndex, 10)
      ) {
        if (gpp.type === 'line') {
          this.lineCtx.appendPathFrom = false
          pathFromLine = w.globals.previousPaths[pp].paths[0].d
        } else if (gpp.type === 'area') {
          this.lineCtx.appendPathFrom = false
          pathFromArea = w.globals.previousPaths[pp].paths[0].d

          if (w.config.stroke.show && w.globals.previousPaths[pp].paths[1]) {
            pathFromLine = w.globals.previousPaths[pp].paths[1].d
          }
        }
      }
    }

    return {
      pathFromLine,
      pathFromArea,
    }
  }

  /** @param {{i: any, realIndex: any, series: any, prevY: any, lineYPosition: any, translationsIndex: any}} opts */
  determineFirstPrevY({
    i,
    realIndex,
    series,
    prevY,
    lineYPosition,
    translationsIndex,
  }) {
    const w = this.w
    const stackSeries =
      (w.config.chart.stacked && !w.globals.comboCharts) ||
      (w.config.chart.stacked &&
        w.globals.comboCharts &&
        (!this.w.config.chart.stackOnlyBar ||
          /** @type {any} */ (this.w.config.series[realIndex])?.type ===
            'bar' ||
          /** @type {any} */ (this.w.config.series[realIndex])?.type ===
            'column'))

    if (typeof series[i]?.[0] !== 'undefined') {
      if (stackSeries) {
        if (i > 0) {
          // 1st y value of previous series
          lineYPosition = this.lineCtx.prevSeriesY[i - 1][0]
        } else {
          // the first series will not have prevY values
          lineYPosition = this.lineCtx.zeroY
        }
      } else {
        lineYPosition = this.lineCtx.zeroY
      }
      prevY =
        lineYPosition -
        series[i][0] / this.lineCtx.yRatio[translationsIndex] +
        (this.lineCtx.isReversed
          ? series[i][0] / this.lineCtx.yRatio[translationsIndex]
          : 0) *
          2
    } else {
      // the first value in the current series is null
      if (stackSeries && i > 0 && typeof series[i][0] === 'undefined') {
        // check for undefined value (undefined value will occur when we clear the series while user clicks on legend to hide serieses)
        for (let s = i - 1; s >= 0; s--) {
          // for loop to get to 1st previous value until we get it
          if (series[s][0] !== null && typeof series[s][0] !== 'undefined') {
            lineYPosition = this.lineCtx.prevSeriesY[s][0]
            prevY = lineYPosition
            break
          }
        }
      }
    }
    return {
      prevY,
      lineYPosition,
    }
  }
}
