/**
 * Copyright (c) 2022 - present TinyVue Authors.
 * Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
 *
 * Use of this source code is governed by an MIT-style license.
 *
 * THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
 * BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
 * A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
 *
 */

import { getFormated } from '../chart-core/deps/utils'
import { isNull } from '@opentiny/utils'
import { itemLabel, itemContent, SAAS_DEFAULT_COLORS } from '../chart-core/deps/constants'

const getWaterfallTooltip = (dataType, digit) => {
  let trigger = 'axis'
  let axisPointer = { type: 'shadow', z: 1, shadowStyle: { color: '#f5f5f5' } }
  let formatter = function (items) {
    const item = items[1]

    return [
      `${itemContent(item.name)}<br/>${itemLabel(item.seriesName)}`,
      `${itemContent(getFormated(item.value, dataType, digit))}`
    ].join('')
  }

  return { trigger, axisPointer, formatter }
}

const getWaterfallXAxis = (args) => {
  const { axisVisible, dimension, labelMap, remainName, remainStatus, rows, totalName, xAxisName } = args

  let xAxisData = [totalName].concat(rows.map((row) => row[dimension]))

  remainStatus === 'have-remain' && (xAxisData = xAxisData.concat([remainName]))

  let name = (labelMap && labelMap[xAxisName]) || xAxisName

  const xAxis = { type: 'category', name, splitLine: { show: false }, data: xAxisData, show: axisVisible }
  const axisLine = { show: true, lineStyle: { color: '#191919', opacity: 0.1, width: 2 } }

  return {
    ...xAxis,
    axisLine
  }
}

const getWaterfallYAxis = (args) => {
  const { axisVisible, dataType, digit, labelMap, yAxisName } = args
  let name = !isNull(labelMap[yAxisName]) ? labelMap[yAxisName] : yAxisName
  let formatter = function (val) {
    return getFormated(val, dataType, digit)
  }

  return { type: 'value', name, axisTick: { show: false }, axisLabel: { formatter }, show: axisVisible }
}

const getWaterfallSeries = (args) => {
  const { dataSum, dataType, digit, metrics, remainStatus, rows, t, totalNum } = args
  const seriesBase = { type: 'bar', stack: t('ui.chart.summation') }
  let { dataSumTemp = dataSum, totalNumTemp = totalNum, assistData, mainData } = {}
  const rowData = rows.map((row) => row[metrics])

  if (remainStatus === 'have-remain') {
    assistData = [0].concat(rows.map((row) => (totalNumTemp -= row[metrics]))).concat([0])
    mainData = [totalNum].concat(rowData).concat([totalNum - dataSum])
  } else {
    assistData = [0].concat(rows.map((row) => (dataSumTemp -= row[metrics])))
    mainData = [dataSum].concat(rowData)
  }

  const series = []
  let seriesAdv = {
    name: t('ui.chart.auxiliary'),
    itemStyle: { opacity: 0 },
    emphasis: { itemStyle: { opacity: 0 } },
    data: assistData
  }

  series.push(Object.assign(seriesAdv, seriesBase))

  let formatter = function (item) {
    return getFormated(item.value, dataType, digit)
  }

  seriesAdv = {
    name: t('ui.chart.value'),
    label: { show: true, position: 'top', formatter },
    data: mainData
  }

  series.push(
    Object.assign(seriesAdv, {
      ...seriesBase,
      itemStyle: { borderRadius: [4, 4, 0, 0] },
      color: SAAS_DEFAULT_COLORS[0]
    })
  )

  return series
}

const getWaterfallRemainStatus = (dataSum, totalNum) =>
  !totalNum ? 'not-total' : totalNum <= dataSum ? 'none-remain' : 'have-remain'

export const waterfall = (columns, rows, settings, extra) => {
  const { tooltipVisible, t } = extra
  const { axisVisible = true, dataType = 'normal', dimension = columns[0] } = settings
  const { remainName = t('ui.chart.other'), totalName = t('ui.chart.total') } = settings
  const { totalNum, xAxisName = dimension, digit = 2, labelMap = {} } = settings

  let metricsTemp = columns.slice()

  metricsTemp.splice(metricsTemp.indexOf(dimension), 1)

  const { metrics = metricsTemp[0], yAxisName = metrics } = {}
  const tooltip = tooltipVisible && getWaterfallTooltip(dataType, digit)

  const dataSum = parseFloat(rows.reduce((pre, cur) => pre + Number(cur[metrics]), 0).toFixed(digit))
  const remainStatus = getWaterfallRemainStatus(dataSum, totalNum)
  const xAxisParams = { dimension, rows, remainStatus, totalName }

  Object.assign(xAxisParams, { remainName, xAxisName, labelMap, axisVisible })

  const xAxis = getWaterfallXAxis(xAxisParams)
  const yAxisParams = { dataType, yAxisName, axisVisible, digit, labelMap }
  const yAxis = getWaterfallYAxis(yAxisParams)
  const seriesParams = { dataType, rows, dimension, metrics }

  Object.assign(seriesParams, { totalNum, remainStatus, dataSum, digit, t })

  const series = getWaterfallSeries(seriesParams)

  return { series, tooltip, xAxis, yAxis }
}
