import Graphics from '../Graphics'
import Series from '../Series'

/**
 * ApexCharts Tooltip.Position Class to move the tooltip based on x and y position.
 *
 * @module Tooltip.Position
 **/

export default class Position {
  constructor(tooltipContext) {
    this.ttCtx = tooltipContext
    this.ctx = tooltipContext.ctx
    this.w = tooltipContext.w
  }

  /**
   * This will move the crosshair (the vertical/horz line that moves along with mouse)
   * Along with this, this function also calls the xaxisMove function
   * @memberof Position
   * @param {int} - cx = point's x position, wherever point's x is, you need to move crosshair
   */
  moveXCrosshairs(cx, j = null) {
    const ttCtx = this.ttCtx
    let w = this.w

    const xcrosshairs = ttCtx.getElXCrosshairs()

    let x = cx - ttCtx.xcrosshairsWidth / 2

    let tickAmount = w.globals.labels.slice().length
    if (j !== null) {
      x = (w.globals.gridWidth / tickAmount) * j
    }

    if (
      w.config.xaxis.crosshairs.width === 'tickWidth' ||
      w.config.xaxis.crosshairs.width === 'barWidth'
    ) {
      if (x + ttCtx.xcrosshairsWidth > w.globals.gridWidth) {
        x = w.globals.gridWidth - ttCtx.xcrosshairsWidth
      }
    } else {
      if (j !== null) {
        x = x + w.globals.gridWidth / tickAmount / 2
      }
    }

    if (x < 0) {
      x = 0
    }

    if (x > w.globals.gridWidth) {
      x = w.globals.gridWidth
    }

    if (xcrosshairs !== null) {
      xcrosshairs.setAttribute('x', x)
      xcrosshairs.setAttribute('x1', x)
      xcrosshairs.setAttribute('x2', x)
      xcrosshairs.setAttribute('y2', w.globals.gridHeight)
      xcrosshairs.classList.add('active')
    }

    if (ttCtx.blxaxisTooltip) {
      let tx = x
      if (
        w.config.xaxis.crosshairs.width === 'tickWidth' ||
        w.config.xaxis.crosshairs.width === 'barWidth'
      ) {
        tx = x + ttCtx.xcrosshairsWidth / 2
      }
      this.moveXAxisTooltip(tx)
    }
  }

  /**
   * This will move the crosshair (the vertical/horz line that moves along with mouse)
   * Along with this, this function also calls the xaxisMove function
   * @memberof Position
   * @param {int} - cx = point's x position, wherever point's x is, you need to move crosshair
   */
  moveYCrosshairs(cy) {
    const ttCtx = this.ttCtx

    if (ttCtx.ycrosshairs !== null) {
      Graphics.setAttrs(ttCtx.ycrosshairs, {
        y1: cy,
        y2: cy
      })

      Graphics.setAttrs(ttCtx.ycrosshairsHidden, {
        y1: cy,
        y2: cy
      })
    }
  }

  /**
   ** AxisTooltip is the small rectangle which appears on x axis with x value, when user moves
   * @memberof Position
   * @param {int} - cx = point's x position, wherever point's x is, you need to move
   */
  moveXAxisTooltip(cx) {
    let w = this.w
    const ttCtx = this.ttCtx

    if (ttCtx.xaxisTooltip !== null) {
      ttCtx.xaxisTooltip.classList.add('active')

      let cy =
        ttCtx.xaxisOffY +
        w.config.xaxis.tooltip.offsetY +
        w.globals.translateY +
        1 +
        w.config.xaxis.offsetY

      let xaxisTTText = ttCtx.xaxisTooltip.getBoundingClientRect()
      let xaxisTTTextWidth = xaxisTTText.width

      cx = cx - xaxisTTTextWidth / 2

      if (!isNaN(cx)) {
        cx = cx + w.globals.translateX

        let textRect = 0
        const graphics = new Graphics(this.ctx)
        textRect = graphics.getTextRects(ttCtx.xaxisTooltipText.innerHTML)

        ttCtx.xaxisTooltipText.style.minWidth = textRect.width + 'px'
        ttCtx.xaxisTooltip.style.left = cx + 'px'
        ttCtx.xaxisTooltip.style.top = cy + 'px'
      }
    }
  }

  moveYAxisTooltip(index) {
    const w = this.w
    const ttCtx = this.ttCtx

    if (ttCtx.yaxisTTEls === null) {
      ttCtx.yaxisTTEls = w.globals.dom.baseEl.querySelectorAll(
        '.apexcharts-yaxistooltip'
      )
    }

    const ycrosshairsHiddenRectY1 = parseInt(
      ttCtx.ycrosshairsHidden.getAttribute('y1')
    )
    let cy = w.globals.translateY + ycrosshairsHiddenRectY1

    const yAxisTTRect = ttCtx.yaxisTTEls[index].getBoundingClientRect()
    const yAxisTTHeight = yAxisTTRect.height
    let cx = w.globals.translateYAxisX[index] - 2

    if (w.config.yaxis[index].opposite) {
      cx = cx - 26
    }

    cy = cy - yAxisTTHeight / 2

    if (w.globals.ignoreYAxisIndexes.indexOf(index) === -1) {
      ttCtx.yaxisTTEls[index].classList.add('active')
      ttCtx.yaxisTTEls[index].style.top = cy + 'px'
      ttCtx.yaxisTTEls[index].style.left =
        cx + w.config.yaxis[index].tooltip.offsetX + 'px'
    } else {
      ttCtx.yaxisTTEls[index].classList.remove('active')
    }
  }

  /**
   ** moves the whole tooltip by changing x, y attrs
   * @memberof Position
   * @param {int} - cx = point's x position, wherever point's x is, you need to move tooltip
   * @param {int} - cy = point's y position, wherever point's y is, you need to move tooltip
   * @param {int} - r = point's radius
   */
  moveTooltip(cx, cy, r = null) {
    let w = this.w

    let ttCtx = this.ttCtx
    const tooltipEl = ttCtx.getElTooltip()
    let tooltipRect = ttCtx.tooltipRect

    let pointR = r !== null ? parseInt(r) : 1

    let x = parseInt(cx) + pointR + 5
    let y = parseInt(cy) + pointR / 2 // - tooltipRect.ttHeight / 2

    if (x > w.globals.gridWidth / 2) {
      x = x - tooltipRect.ttWidth - pointR - 15
    }

    if (x > w.globals.gridWidth - tooltipRect.ttWidth - 10) {
      x = w.globals.gridWidth - tooltipRect.ttWidth
    }

    if (x < -20) {
      x = -20
    }

    if (w.config.tooltip.followCursor) {
      const elGrid = ttCtx.getElGrid()
      const seriesBound = elGrid.getBoundingClientRect()
      y =
        ttCtx.e.clientY +
        w.globals.translateY -
        seriesBound.top -
        tooltipRect.ttHeight / 2
    }

    const newPositions = this.positionChecks(tooltipRect, x, y)
    x = newPositions.x
    y = newPositions.y

    if (!isNaN(x)) {
      x = x + w.globals.translateX

      tooltipEl.style.left = x + 'px'
      tooltipEl.style.top = y + 'px'
    }
  }

  positionChecks(tooltipRect, x, y) {
    const w = this.w
    if (tooltipRect.ttHeight + y > w.globals.gridHeight) {
      y = w.globals.gridHeight - tooltipRect.ttHeight + w.globals.translateY
    }

    if (y < 0) {
      y = 0
    }

    return {
      x,
      y
    }
  }

  moveMarkers(i, j) {
    let w = this.w
    let ttCtx = this.ttCtx

    if (w.globals.markers.size[i] > 0) {
      let allPoints = w.globals.dom.baseEl.querySelectorAll(
        ` .apexcharts-series[data\\:realIndex='${i}'] .apexcharts-marker`
      )
      for (let p = 0; p < allPoints.length; p++) {
        if (parseInt(allPoints[p].getAttribute('rel')) === j) {
          ttCtx.marker.resetPointsSize()
          ttCtx.marker.enlargeCurrentPoint(j, allPoints[p])
        }
      }
    } else {
      ttCtx.marker.resetPointsSize()
      this.moveDynamicPointOnHover(j, i)
    }
  }

  // This function is used when you need to show markers/points only on hover -
  // DIFFERENT X VALUES in multiple series
  moveDynamicPointOnHover(j, capturedSeries) {
    let w = this.w
    let ttCtx = this.ttCtx
    let cx = 0
    let cy = 0

    let pointsArr = w.globals.pointsArray

    let hoverSize = w.config.markers.hover.size

    if (hoverSize === undefined) {
      hoverSize =
        w.globals.markers.size[capturedSeries] +
        w.config.markers.hover.sizeOffset
    }

    cx = pointsArr[capturedSeries][j][0]
    cy = pointsArr[capturedSeries][j][1] ? pointsArr[capturedSeries][j][1] : 0

    let point = w.globals.dom.baseEl.querySelector(
      `.apexcharts-series[data\\:realIndex='${capturedSeries}'] .apexcharts-series-markers circle`
    )

    if (point) {
      point.setAttribute('r', hoverSize)

      point.setAttribute('cx', cx)
      point.setAttribute('cy', cy)
    }

    // point.style.opacity = w.config.markers.hover.opacity

    this.moveXCrosshairs(cx)

    if (!ttCtx.fixedTooltip) {
      this.moveTooltip(cx, cy, hoverSize)
    }
  }

  // This function is used when you need to show markers/points only on hover -
  // SAME X VALUES in multiple series
  moveDynamicPointsOnHover(j) {
    const ttCtx = this.ttCtx
    let w = ttCtx.w
    let cx = 0
    let cy = 0
    let activeSeries = 0

    let pointsArr = w.globals.pointsArray

    let series = new Series(this.ctx)
    activeSeries = series.getActiveSeriesIndex()

    let hoverSize = w.config.markers.hover.size
    if (hoverSize === undefined) {
      hoverSize =
        w.globals.markers.size[activeSeries] + w.config.markers.hover.sizeOffset
    }

    if (pointsArr[activeSeries]) {
      cx = pointsArr[activeSeries][j][0]
      cy = pointsArr[activeSeries][j][1]
    }

    let points = null
    const allPoints = ttCtx.getAllMarkers()

    if (allPoints !== null) {
      points = allPoints
    } else {
      points = w.globals.dom.baseEl.querySelectorAll(
        '.apexcharts-series-markers circle'
      )
    }

    if (points !== null) {
      for (let p = 0; p < points.length; p++) {
        let pointArr = pointsArr[p]

        if (pointArr && pointArr.length) {
          let pcy = pointsArr[p][j][1]
          points[p].setAttribute('cx', cx)
          let realIndex = parseInt(
            points[p].parentNode.parentNode.parentNode.getAttribute(
              'data:realIndex'
            )
          )

          if (pcy !== null) {
            points[realIndex] && points[realIndex].setAttribute('r', hoverSize)
            points[realIndex] && points[realIndex].setAttribute('cy', pcy)
          } else {
            points[realIndex] && points[realIndex].setAttribute('r', 0)
          }
        }
      }
    }

    this.moveXCrosshairs(cx)

    if (!ttCtx.fixedTooltip) {
      let tcy = cy || w.globals.gridHeight
      this.moveTooltip(cx, tcy, hoverSize)
    }
  }

  moveStickyTooltipOverBars(j) {
    const w = this.w
    const ttCtx = this.ttCtx

    let jBar = w.globals.dom.baseEl.querySelector(
      `.apexcharts-bar-series .apexcharts-series[rel='1'] path[j='${j}'], .apexcharts-candlestick-series .apexcharts-series[rel='1'] path[j='${j}'], .apexcharts-rangebar-series .apexcharts-series[rel='1'] path[j='${j}']`
    )

    let bcx = jBar ? parseFloat(jBar.getAttribute('cx')) : 0
    let bcy = 0
    let bw = jBar ? parseFloat(jBar.getAttribute('barWidth')) : 0

    if (w.globals.isXNumeric) {
      bcx = bcx - bw / 2
    } else {
      bcx = ttCtx.xAxisTicksPositions[j - 1] + ttCtx.dataPointsDividedWidth / 2
      if (isNaN(bcx)) {
        bcx = ttCtx.xAxisTicksPositions[j] - ttCtx.dataPointsDividedWidth / 2
      }
    }

    // tooltip will move vertically along with mouse as it is a shared tooltip
    const elGrid = ttCtx.getElGrid()
    let seriesBound = elGrid.getBoundingClientRect()

    bcy = ttCtx.e.clientY - seriesBound.top - ttCtx.tooltipRect.ttHeight / 2

    this.moveXCrosshairs(bcx)

    if (!ttCtx.fixedTooltip) {
      let tcy = bcy || w.globals.gridHeight
      this.moveTooltip(bcx, tcy)
    }
  }
}
