<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 './newStatisticsHeader.vue'
import { Query } from '@/api/webApi'
import { mapGetters } from 'vuex'
import * as XLSX from 'xlsx'
import XLSX_STYLE from 'xlsx-style'
import FileSaver from 'file-saver'

export default {
  name: 'NewPieStatisticsCharts',
  components: { StatisticsHeader },
  props: {
    chartsTitle: {
      type: String,
      required: true,
    },
    querySettings: {
      type: Object,
      required: true,
    },
    categories: {
      type: Array,
      required: true,
    },
    customFormItems: {
      type: Array,
      default: () => [],
    },
    pieTitle: {
      type: String,
      default: '总件数',
    },
  },
  data() {
    return {
      myChart: null,
      debounceTime: 300,
      chartHeight: '70vh',
      hasChartData: false,
      filters: [],
      tableData: [],
      params: [],
      totalCount: [{ value: 0 }],
      categoryDatas: [],
      categoryKey: 'specialnum',
      baseKey: 'special',
      options: {
        backgroundColor: '#ffffff',
        tooltip: {
          trigger: 'item',
        },
        title: {
          text: '',
          // 副标题
          subtext: '0',
          // 主副标题间距
          itemGap: 24,
          x: 'left',
          y: 'center',
          left: '30%',
          top: '40%',
          textAlign: 'center',
          // 主标题样式
          textStyle: {
            fontSize: '48',
            color: '#ffffff',
            fontWeight: 'bold',
            fontFamily: 'Microsoft YaHei',
          },
          // 副标题样式
          subtextStyle: {
            fontSize: '80',
            color: '#ffffff',
            fontWeight: 'bold',
          },
        },
        legend: {
          show: true,
          left: '60%',
          x: 'right',
          y: 'center',
          icon: 'rect',
          itemWidth: 20,
          itemHeight: 20,
          formatter: name => this.legendFormatter(name),
          textStyle: {
            backgroundColor: 'transparent',
            lineHeight: 0,
            rich: {
              chartsTitle: {
                width: 200,
                lineHeight: 100,
                fontSize: 32,
                fontFamily: 'Microsoft YaHei',
                fontWeight: 'bold',
                color: '#101116',
                padding: [0, 1000, 0, -20],
              },
              name: {
                fontSize: 20,
                fontFamily: 'Microsoft YaHei',
                fontWeight: 'bold',
                color: '#101116',
                lineHeight: 100,
              },
              label: {
                fontSize: 16,
                fontFamily: 'Microsoft YaHei',
                color: '#101116',
              },
              value: {
                width: 96,
                fontSize: 16,
                fontFamily: 'Helvetica',
                fontWeight: 'bold',
                color: '#101116',
              },
              ratio: {
                width: 80,
                fontSize: 16,
                fontFamily: 'Helvetica',
                fontWeight: 'bold',
                color: '#101116',
              },
              wrap: {
                padding: [0, 40, 0, 0],
              },
            },
          },
          selected: {
            [this.chartsTitle]: false,
          },
        },
        series: [
          {
            name: '',
            type: 'pie',
            left: '30%',
            width: 560,
            height: 560,
            center: [0, '60%'],
            radius: ['60%', '90%'],
            avoidLabelOverlap: false,
            label: {
              show: false,
              position: 'center',
            },
            emphasis: {
              label: {
                show: false,
                fontSize: '40',
                fontWeight: 'bold',
              },
            },
            labelLine: {
              show: false,
            },
            data: [],
          },
          {
            name: '总数',
            type: 'pie',
            left: '30%',
            width: 560,
            height: 560,
            center: [0, '60%'],
            radius: ['0%', '50%'],
            avoidLabelOverlap: false,
            itemStyle: {
              normal: {
                color: '#101116',
              },
            },
            label: {
              show: false,
              position: 'center',
            },
            // 自定义中心内容的话需要把这个关闭
            emphasis: {
              label: {
                show: false,
              },
            },
            labelLine: {
              show: false,
            },
            data: [],
          },
        ],
      },
    }
  },
  computed: {
    ...mapGetters(['sidebar']),
    seriesKey() {
      const filterMap = {
        全部: '',
        进港: '_in',
        离港: '_out',
      }
      return `${this.baseKey}${this.filters
        .map(filter => filterMap[filter])
        .join('')}`
    },
  },
  watch: {
    pieTitle: {
      handler(val) {
        this.options.title.text = val
      },
      immediate: true,
    },
    // 监听数据变化 重绘图形
    options: {
      handler(obj) {
        this.myChart.setOption(obj)
        this.resizeHandler()
      },
      deep: true,
    },
    categories: {
      handler(arr) {
        this.categoryDatas = arr.map(categoryName => ({
          name: categoryName,
          value: 0,
        }))
        this.categoryDatas.unshift({
          name: this.chartsTitle,
          value: null,
        })
      },
      deep: true,
      immediate: true,
    },
    querySettings: {
      handler({ categoryKey, seriesKey }) {
        if (seriesKey) {
          this.baseKey = seriesKey
        }
        if (categoryKey) {
          this.categoryKey = categoryKey
        }
      },
      deep: true,
      immediate: true,
    },
    'sidebar.expand'() {
      this.setChartHeight()
    },
  },
  mounted() {
    this.setChartHeight()
    this.myChart = this.$echarts.init(document.getElementById('chart'))
    this.options.series[0].data = this.categoryDatas
    this.options.legend.data = this.categoryDatas.map(({ name }, index) => {
      if (index === 0) {
        return {
          name,
          icon: 'none',
        }
      } else {
        return {
          name,
        }
      }
    })
    this.options.series[1].data = this.totalCount
    this.myChart.setOption(this.options)
    this.myChart.on('legendselectchanged', ({ name }) => {
      if (name === this.chartsTitle) {
        this.myChart.dispatchAction({
          type: 'legendUnSelect',
          name,
        })
      }
    })
    // 监听页面缩放
    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: {
    legendFormatter(name) {
      const index = this.categoryDatas.findIndex(
        category => category.name === name
      )
      if (index === 0) {
        return `{chartsTitle|${name}}`
      } else {
        const value = this.categoryDatas[index].value
        const ratio =
          value && this.totalCount.value
            ? ((value / this.totalCount.value) * 100).toFixed(2) + '%'
            : '0%'
        const richString = `{name|${name}}\n{label|数量：}{value|${value}}{label|占比：}{ratio|${ratio}}`
        return index % 2 ? richString + '{wrap| }' : richString
      }
    },
    resetDatas() {
      this.hasChartData = false
      this.categoryDatas.forEach(category => {
        category && (category.value = 0)
      })
      this.options.title.subtext = '0'
      this.options.series[1].data[0].value = 0
    },
    getFormData(formData) {
      this.resetDatas()

      let serviceId
      let dataContentList = []
      const dataContent = {
        IATA: 'CA',
        td: formData.interval,
        fd1: formData.dateTime[0],
        fd2: formData.dateTime[1],
      }
      switch (formData.range) {
        case '全部':
          serviceId = SERVICE_ID.flightClassificationAll
          dataContentList = [dataContent]
          break
        case '基地分公司':
          serviceId = SERVICE_ID.flightClassificationAll
          dataContentList = [
            {
              ...dataContent,
              IATA: formData.area,
            },
          ]
          break
        case '航线':
          serviceId = SERVICE_ID.flightClassificationByAirline
          dataContentList =
            formData.airline instanceof Array
              ? formData.airline.map(airline => ({
                  ...dataContent,
                  air_line: airline,
                }))
              : [
                  {
                    ...dataContent,
                    air_line: formData.airline,
                  },
                ]
          break
        case '航站':
          serviceId = SERVICE_ID.flightClassificationByAirport
          dataContentList =
            formData.airport instanceof Array
              ? formData.airport.map(airport => ({
                  ...dataContent,
                  airport,
                }))
              : [
                  {
                    ...dataContent,
                    airport: formData.airport,
                  },
                ]
          break
        case '航站楼':
          serviceId = SERVICE_ID.flightClassificationByTerminal
          dataContentList = [
            {
              ...dataContent,
              airport: formData.terminal.split('-')[0],
              terminal: formData.terminal.split('-')[1],
            },
          ]
          break
        default:
          return
      }
      this.filters = this.querySettings.filters || []
      this.filters.push(formData.inOrOut)
      const rangeMap = {
        航线: 'airline',
        基地分公司: 'area',
        航站: 'airport',
        航站楼: 'terminal',
      }
      this.params = [
        formData.interval,
        formData.range,
        formData[rangeMap[formData.range]],
        formData.inOrOut,
        formData.dateTime[0],
        formData.dateTime[1],
        ...this.filters,
      ]
      this.getMultipleChartsData(serviceId, dataContentList)
    },
    async getMultipleChartsData(serviceId, dataContentList) {
      try {
        const listValuesArray = await Promise.all(
          dataContentList.map(dataContent =>
            this.getChartsData(serviceId, dataContent)
          )
        )
        const listValues = listValuesArray.reduce(
          (preValues, currentValues) => {
            currentValues.forEach(value => {
              const preValue = preValues.find(
                preValue =>
                  preValue.fd === value.fd &&
                  preValue[this.categoryKey] === value[this.categoryKey]
              )
              if (preValue) {
                preValue[this.seriesKey] += value[this.seriesKey]
              } else {
                preValues.push({
                  fd: value.fd,
                  [this.categoryKey]: value[this.categoryKey],
                  [this.seriesKey]: value[this.seriesKey],
                })
              }
            })
            return preValues
          },
          []
        )
        this.setChartsData(listValues)
        this.tableData = listValuesArray
          .map(list =>
            this._.sortBy(list, 'fd', o =>
              this.categories.indexOf(o.flight_attr)
            )
          )
          .flat()
      } catch (error) {
        this.$message.error(error.message)
      }
    },
    async getChartsData(serviceId, dataContent) {
      try {
        const { code, returnData, message } = await Query({
          serviceId,
          dataContent,
          event: '0',
        })
        if (String(code) === '0') {
          return returnData
        } else {
          return Promise.reject(message || '失败')
        }
      } catch (error) {
        return Promise.reject(error.message || '失败')
      }
    },
    setChartsData(listValues) {
      if (listValues.length === 0) {
        this.$message.info('未查询到对应数据')
        return
      }
      let totalCount = 0
      listValues.forEach(element => {
        this.categoryDatas.forEach(category => {
          if (element[this.categoryKey]?.includes(category.name)) {
            category.value += element[this.seriesKey]
          }
        })
        totalCount += element[this.seriesKey]
      })
      this.options.title.subtext = totalCount.toString()
      this.totalCount.value = totalCount
      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 = [['时间', '位置', '分类', '数量', '占比']]
      xlsxDatas.push(
        ...this.tableData.map(element => [
          element['fd'],
          element['location'],
          element[this.categoryKey],
          element[this.seriesKey],
          ((element[this.seriesKey] / this.totalCount.value) * 100).toFixed(2) +
            '%',
        ])
      )
      xlsxDatas.push(['合计', '', '', this.totalCount.value, ''])
      // 计算列宽
      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 = reg.test(key)
        if (match) {
          const rowIndex = reg.exec(key)[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'
          }
          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>
