<template>
  <div class="statstics-wrapper">
    <div
      ref="headerWrapper"
      class="statstics-header"
    >
      <StatisticsHeader
        :title="`${chartsTitle}统计`"
        :custom-items="customFormItems"
        @getFormData="getFormData"
        @export="exportHandler"
      />
    </div>
    <div class="statstics-content">
      <div
        id="chart"
        class="statistics-chart"
        :style="{ height: chartHeight }"
      />
    </div>
  </div>
</template>

<script>
import StatisticsHeader from './statisticsHeader.vue'
import { TempQuery } from '@/api/temp'
import { mapGetters } from 'vuex'
import * as XLSX from 'xlsx'
import XLSX_STYLE from 'xlsx-style'
import FileSaver from 'file-saver'

export default {
  name: 'CommonBarStatisticsCharts',
  components: { StatisticsHeader },
  props: {
    chartsTitle: {
      type: String,
      required: true
    },
    querySettings: {
      type: Object,
      required: true
    },
    customFormItems: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      myChart: null,
      debounceTime: 300,
      chartHeight: '70vh',
      hasChartData: false,
      seriesKey: 'seriesData',
      filters: [],
      tableData: [],
      params: [],
      options: {
        backgroundColor: '#fff',
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross',
            crossStyle: {
              color: '#999'
            }
          }
        },
        legend: {
          top: '5%',
          right: '5%',
          icon: 'rect',
          height: 14,
          itemWidth: 14,
          itemHeight: 14,
          itemGap: 30,
          data: [
            this.chartsTitle.replace('量', '数量'),
            // `${this.chartsTitle}量同比`,
            `${this.chartsTitle}环比`
          ],
          textStyle: {
            fontFamily: 'Helvetica, "Microsoft YaHei"',
            color: '#101116'
          }
        },
        grid: {
          top: '15%',
          left: '5%',
          right: '5%',
          bottom: '5%'
        },
        xAxis: {
          data: [],
          axisLine: {
            show: true,
            lineStyle: {
              color: '#000000'
            }
          },
          axisTick: {
            show: false // 隐藏X轴刻度
          },
          axisLabel: {
            fontFamily: 'Helvetica, "Microsoft YaHei"',
            color: '#101116'
          },
          axisPointer: {
            type: 'shadow'
          }
        },
        yAxis: [
          {
            min: 0,
            max: 60000,
            splitLine: {
              lineStyle: {
                type: 'dashed',
                color: '#B0B3C3',
                opacity: 0.5
              }
            },
            axisPointer: {
              label: {
                formatter: ({ value }) => value.toFixed()
              }
            },
            axisLabel: {
              fontFamily: 'Helvetica, "Microsoft YaHei"',
              color: '#101116'
            }
          },
          {
            min: -0.3,
            max: 0.5,
            axisLabel: {
              formatter: value => (value * 100).toFixed(2) + '%',
              fontFamily: 'Helvetica, "Microsoft YaHei"',
              color: '#101116'
            },
            axisPointer: {
              label: {
                formatter: ({ value }) => (value * 100).toFixed(2) + '%'
              }
            },
            splitLine: {
              show: false
            }
          }
        ],
        series: [
          {
            name: this.chartsTitle.replace('量', '数量'),
            type: 'bar',
            z: 2,
            itemStyle: {
              color: '#6682B5'
            },
            barWidth: 40,
            label: {
              show: true,
              position: 'top'
            },
            data: []
          },
          {
            name: `${this.chartsTitle}同比`,
            type: 'line',
            z: 4,
            yAxisIndex: 1,
            symbol: 'circle',
            itemStyle: {
              color: '#F2B849',
              borderColor: '#ffffff',
              borderWidth: 4
            },
            lineStyle: {
              width: 4,
              color: '#F2B849'
            },
            symbolSize: 32,
            tooltip: {
              valueFormatter: value => (value * 100).toFixed(2) + '%'
            },
            data: []
          },
          {
            name: `${this.chartsTitle}环比`,
            type: 'line',
            z: 3,
            yAxisIndex: 1,
            symbol: 'circle',
            itemStyle: {
              color: '#E33D3D',
              borderColor: '#ffffff',
              borderWidth: 4
            },
            lineStyle: {
              width: 4,
              color: '#E33D3D'
            },
            symbolSize: 32,
            tooltip: {
              valueFormatter: value => (value * 100).toFixed(2) + '%'
            },
            data: []
          }
        ]
      }
    }
  },
  computed: {
    ...mapGetters(['sidebar'])
  },
  watch: {
    // 监听数据变化 重绘图形
    options: {
      handler(obj) {
        this.myChart.setOption(obj)
        this.resizeHandler()
      },
      deep: true
    },
    'sidebar.expand'() {
      this.setChartHeight()
    },
    querySettings: {
      handler({ seriesKey, filters }) {
        if (seriesKey) {
          this.seriesKey = seriesKey
        }
        if (filters?.length) {
          this.filters = filters
        }
      },
      deep: true,
      immediate: true
    }
  },
  mounted() {
    this.setChartHeight()
    this.myChart = this.$echarts.init(document.getElementById('chart'))
    this.myChart.setOption(this.options)
    // 监听页面缩放
    this.debouncedChartHeightSetter = this._.debounce(this.setChartHeight, this.debounceTime)
    window.addEventListener('resize', this.debouncedChartHeightSetter)
  },
  beforeDestroy() {
    // 销毁实例和移除监听
    window.removeEventListener('resize', this.debouncedChartHeightSetter)
    if (this.myChart) {
      this.myChart.dispose()
      this.myChart = null
    }
  },
  methods: {
    resetDatas() {
      this.hasChartData = false
      this.options.yAxis[0].max = 60000
      this.options.xAxis.data = []
      this.options.series[0].data = []
      this.options.series[2].data = []
      this.options.yAxis[1].min = -0.3
      this.options.yAxis[1].max = 0.5
    },
    getFormData(formData) {
      this.resetDatas()

      let id
      let params = []
      if (formData.range === '基地分公司') {
        if (formData.flightType === '有行李') {
          id = this.querySettings.withBaggageByArea
        } else if (formData.baggageType === '不包含DEL') {
          id = this.querySettings.notDelByArea
        } else if (formData.passengerType[0] === '要客类型') {
          id = this.querySettings.importantByArea
        } else {
          id = this.querySettings.byArea
        }
        params = [formData.interval, formData.area, formData.inOrOut, formData.dateTime[0], formData.dateTime[1]]
      } else {
        if (formData.flightType === '有行李') {
          id = this.querySettings.withBaggageByOther
        } else if (formData.baggageType === '不包含DEL') {
          id = this.querySettings.notDelByOther
        } else if (formData.passengerType[0] === '要客类型') {
          id = this.querySettings.importantByOther
        } else {
          id = this.querySettings.byOther
        }
        params = [formData.interval, formData.range, formData.inOrOut, formData.dateTime[0], formData.dateTime[1]]
        if (formData.airline.length) {
          params.splice(2, 0, formData.airline)
        } else if (formData.airport.length) {
          params.splice(2, 0, formData.airport)
        } else if (formData.terminal !== '') {
          params.splice(2, 0, formData.terminal)
        } else {
          params.splice(2, 0, '全部')
        }
      }
      if (formData.passengerType.length) {
        this.filters = [
          {
            key: formData.passengerType[0],
            value: formData.passengerType[1]
          }
        ]
      }
      this.params = [...params, ...this.filters.map(({ value }) => value)]
      if (params[2] instanceof Array) {
        const paramsList = params[2].map(param => [...params.slice(0, 2), param, ...params.slice(3)])
        this.getMultipleChartsData(id, paramsList)
      } else {
        this.getSingleChartsData(id, params)
      }
    },
    async getMultipleChartsData(id, paramsList) {
      try {
        const listValuesArray = await Promise.all(paramsList.map(params => this.getChartsData(id, params)))
        const listValues = listValuesArray.reduce((preValues, currentValues) => {
          currentValues.forEach(value => {
            const preValue = preValues.find(preValue => preValue.A === value.A)
            if (preValue) {
              preValue[this.seriesKey] += value[this.seriesKey]
            } else {
              preValues.push({
                A: value.A,
                [this.seriesKey]: value[this.seriesKey]
              })
            }
          })
          return preValues
        }, [])
        this.setChartsData(this._.sortBy(listValues, 'A'))
      } catch (error) {
        this.$message.error(error.message)
      }
    },
    async getSingleChartsData(id, params) {
      try {
        const listValues = await this.getChartsData(id, params)
        this.setChartsData(listValues)
      } catch (error) {
        this.$message.error(error.message)
      }
    },
    async getChartsData(id, params) {
      try {
        const {
          code,
          returnData: { listValues },
          message
        } = await TempQuery({
          id,
          dataContent: params
        })
        if (Number(code) === 0) {
          return listValues
        } else {
          return Promise.reject(message || '失败')
        }
      } catch (error) {
        return Promise.reject(error.message || '失败')
      }
    },
    setChartsData(listValues) {
      const xAxisData = []
      const yAxisData = [0]
      const seriesDatas = []
      const filteredList = listValues.filter(element =>
        this.filters.every((key, value) => {
          if (key && value && element[key] !== value) {
            return false
          } else {
            return true
          }
        })
      )
      if (filteredList.length === 0) {
        this.$message.info('未查询到对应数据')
        return
      }
      for (let i = 0; i < filteredList.length; i++) {
        xAxisData.push(filteredList[i].A)
        seriesDatas.push(filteredList[i][this.seriesKey])
        if (i > 0) {
          if (filteredList[i - 1][this.seriesKey] > 0) {
            yAxisData.push(
              (filteredList[i][this.seriesKey] - filteredList[i - 1][this.seriesKey]) /
                filteredList[i - 1][this.seriesKey]
            )
          } else {
            yAxisData.push(0)
          }
        }
      }
      let max = Math.max(...seriesDatas)
      max = Math.ceil(max / 10) * 10
      this.options.yAxis[0].max = max
      this.options.xAxis.data = xAxisData
      this.options.series[0].data = seriesDatas
      this.options.series[2].data = yAxisData
      this.options.yAxis[1].min = (Math.min(...yAxisData) - 0.1).toFixed(2)
      this.options.yAxis[1].max = (Math.max(...yAxisData) + 0.1).toFixed(2)
      this.tableData = [xAxisData, seriesDatas, yAxisData]
      this.hasChartData = true
    },
    setChartHeight() {
      const topBarHeight = 80
      const headerBlankHeight = 24
      const tabsWrapperHeight = 62
      const headerHeight = this.$refs['headerWrapper'].offsetHeight
      const footerBlankHeight = 24
      this.chartHeight = `calc(100vh - ${
        topBarHeight + headerBlankHeight + tabsWrapperHeight + headerHeight + footerBlankHeight
      }px)`
      this.$nextTick(() => {
        this.resizeHandler()
      })
    },
    resizeHandler() {
      if (this.myChart) {
        this.myChart.resize()
      }
    },
    exportHandler() {
      if (!this.hasChartData) {
        this.$message.warning('请查询后再进行导出')
        return
      }
      // const myCanvas = this.myChart._dom.querySelectorAll('canvas')[0]
      // const image = myCanvas.toDataURL('image/png')
      // const $a = document.createElement('a')
      // $a.setAttribute('href', image)
      // $a.setAttribute('download', `${this.chartsTitle}统计.png`)
      // $a.click()

      // 生成表格数据
      const xlsxDatas = [['时间', this.chartsTitle.replace('量', '数量'), `${this.chartsTitle}环比`]]
      const transposition = this.tableData[0].map((col, colIndex) => {
        return this.tableData.map((row, rowIndex) => {
          return rowIndex === 2 ? (row[colIndex] * 100).toFixed(2) + '%' : row[colIndex]
        })
      })
      xlsxDatas.push(...transposition)
      // 添加合计行
      if (xlsxDatas.length > 2) {
        const summaryRow = ['合计']
        const colNum = xlsxDatas[0].length
        for (let colIndex = 1; colIndex < colNum; colIndex++) {
          summaryRow[colIndex] = xlsxDatas.reduce((pre, currentRow, rowIndex) => {
            if (colIndex === 1) {
              if (rowIndex === 0) {
                return 0
              } else {
                return pre + currentRow[colIndex]
              }
            } else {
              return pre
            }
          }, '')
        }
        xlsxDatas.push(summaryRow)
      }
      // 计算列宽
      const columnWidths = []
      xlsxDatas.forEach((row, rowIndex) => {
        // 计算每一列宽度，考虑换行
        row.forEach((cell, columnIndex) => {
          const cellWidth = Math.max(
            ...cell
              .toString()
              .split('\n')
              .map(cellRow =>
                cellRow.split('').reduce((pre, curr) => {
                  const letterSize = curr.charCodeAt(0) > 255 ? 2 : 1
                  return pre + letterSize
                }, 0)
              )
          )
          if ((!columnWidths[columnIndex] && cellWidth > 0) || cellWidth > columnWidths[columnIndex]) {
            columnWidths[columnIndex] = cellWidth
          }
        })
      })
      // 生成表格
      const sheet = XLSX.utils.aoa_to_sheet(xlsxDatas)
      // 添加列宽度
      sheet['!cols'] = columnWidths.map(width => ({
        wch: width + 2
      }))
      // 样式
      const borderStyle = {
        style: 'medium',
        color: {
          rgb: 'FFFFFF'
        }
      }
      const reg = /^[A-Z]+([\d]+$)/
      for (const key in sheet) {
        const match = key.match(reg)
        if (match) {
          const rowIndex = match[1]
          let cellStyle = {
            alignment: {
              horizontal: 'center',
              vertical: 'center',
              wrapText: true
            }
          }
          if (Number(rowIndex) === 1) {
            cellStyle = {
              ...cellStyle,
              border: {
                top: borderStyle,
                right: borderStyle,
                bottom: borderStyle,
                left: borderStyle
              },
              font: {
                color: {
                  rgb: 'FFFFFF'
                }
              },
              fill: {
                fgColor: {
                  rgb: '3366FF'
                }
              }
            }
          } else {
            cellStyle.alignment.horizontal = 'left'
          }
          const cellValue = sheet[key].v
          const isNumber = /^[^0]/.test(cellValue) && !isNaN(parseFloat(cellValue)) && isFinite(cellValue)
          const isPercentage = /^[0-9]+(\.[0-9]+){0,1}\%$/.test(cellValue)
          if (isNumber) {
            sheet[key] = {
              ...sheet[key],
              t: 'n',
              z: '0',
              v: Number(cellValue)
            }
          }
          if (isPercentage) {
            sheet[key] = {
              ...sheet[key],
              t: 'n',
              z: '0.00%',
              v: parseFloat(cellValue)
            }
          }
          sheet[key].s = cellStyle
        }
      }
      // 表格数据转换
      const workBook = XLSX.utils.book_new()
      XLSX.utils.book_append_sheet(workBook, sheet, this.chartsTitle)
      const tableWrite = XLSX_STYLE.write(workBook, {
        bookType: 'xlsx',
        bookSST: true,
        type: 'buffer',
        cellStyles: true
      })
      // 下载表格
      const fileName = `${this.chartsTitle}统计-${this.params.join('-')}.xlsx`
      FileSaver.saveAs(new Blob([tableWrite], { type: 'application/octet-stream' }), fileName)
    }
  }
}
</script>

<style lang="scss" scoped>
.statistics-chart {
  width: 100%;
}
</style>
