<script setup lang="ts">
import * as echarts from 'echarts/core';
import {
  TooltipComponent,
  TooltipComponentOption,
  GridComponent,
  GridComponentOption,
  LegendComponent,
  LegendComponentOption,
  DataZoomComponent,
  DataZoomComponentOption,
} from 'echarts/components';
import { LineChart, LineSeriesOption } from 'echarts/charts';
import { UniversalTransition } from 'echarts/features';
import { CanvasRenderer } from 'echarts/renderers';

import { reactive, ref, onMounted, toRaw, markRaw, nextTick } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import { message, Modal } from 'ant-design-vue/lib';
import { ColumnsType } from 'ant-design-vue/lib/table';
import { SizeType } from 'ant-design-vue/lib/config-provider';
import { MenuInfo } from 'ant-design-vue/lib/menu/src/interface';
import TableColumnsDnd from '@/components/TableColumnsDnd/index.vue';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import useNeInfoStore from '@/store/modules/neinfo';
import useI18n from '@/hooks/useI18n';
import { getKPITitle, listKPIData } from '@/api/perfManage/goldTarget';
import { parseDateToStr } from '@/utils/date-utils';
import { writeSheet } from '@/utils/execl-utils';
import saveAs from 'file-saver';
import { generateColorRGBA } from '@/utils/generate-utils';
const neInfoStore = useNeInfoStore();
const { t, currentLocale } = useI18n();

echarts.use([
  TooltipComponent,
  GridComponent,
  LegendComponent,
  DataZoomComponent,
  LineChart,
  CanvasRenderer,
  UniversalTransition,
]);

type EChartsOption = echarts.ComposeOption<
  | TooltipComponentOption
  | GridComponentOption
  | LegendComponentOption
  | DataZoomComponentOption
  | LineSeriesOption
>;

/**图DOM节点实例对象 */
const kpiChartDom = ref<HTMLElement | undefined>(undefined);

/**图实例对象 */
const kpiChart = ref<any>(null);

/**网元参数 */
let neCascaderOptions = ref<Record<string, any>[]>([]);

/**记录开始结束时间 */
let queryRangePicker = ref<[string, string]>(['', '']);

/**表格字段列 */
let tableColumns = ref<ColumnsType>([]);

/**表格字段列排序 */
let tableColumnsDnd = ref<ColumnsType>([]);

/**表格分页器参数 */
let tablePagination = reactive({
  /**当前页数 */
  current: 1,
  /**每页条数 */
  pageSize: 20,
  /**默认的每页条数 */
  defaultPageSize: 20,
  /**指定每页可以显示多少条 */
  pageSizeOptions: ['10', '20', '50', '100'],
  /**只有一页时是否隐藏分页器 */
  hideOnSinglePage: false,
  /**是否可以快速跳转至某页 */
  showQuickJumper: true,
  /**是否可以改变 pageSize */
  showSizeChanger: true,
  /**数据总数 */
  total: 0,
  showTotal: (total: number) => t('common.tablePaginationTotal', { total }),
  onChange: (page: number, pageSize: number) => {
    tablePagination.current = page;
    tablePagination.pageSize = pageSize;
  },
});

/**表格状态类型 */
type TabeStateType = {
  /**加载等待 */
  loading: boolean;
  /**紧凑型 */
  size: SizeType;
  /**搜索栏 */
  seached: boolean;
  /**记录数据 */
  data: Record<string, any>[];
  /**显示表格 */
  showTable: boolean;
};

/**表格状态 */
let tableState: TabeStateType = reactive({
  tableColumns: [],
  loading: false,
  size: 'middle',
  seached: true,
  data: [],
  showTable: false,
});

/**表格紧凑型变更操作 */
function fnTableSize({ key }: MenuInfo) {
  tableState.size = key as SizeType;
}

/**查询参数 */
let queryParams: any = reactive({
  /**网元类型 */
  neType: '',
  /**网元标识 */
  neId: '',
  /**颗粒度 */
  interval: 900,
  /**开始时间 */
  startTime: '',
  /**结束时间 */
  endTime: '',
  /**排序字段 */
  sortField: 'timeGroup',
  /**排序方式 */
  sortOrder: 'desc',
});

/**表格分页、排序、筛选变化时触发操作, 排序方式，取值为 ascend descend */
function fnTableChange(pagination: any, filters: any, sorter: any, extra: any) {
  const { columnKey, order } = sorter;
  if (!order) return;
  if (order.startsWith(queryParams.sortOrder)) return;

  if (order) {
    queryParams.sortField = columnKey;
    queryParams.sortOrder = order.replace('end', '');
  } else {
    queryParams.sortOrder = 'asc';
  }

  fnGetList();
}

/**对象信息状态类型 */
type StateType = {
  /**网元类型 */
  neType: string[];
  /**图表配置数据 */
  chartsOption: Record<string, any>;
};

/**对象信息状态 */
let state: StateType = reactive({
  neType: [],
  chartsOption: {},
});

function fnChangShowType() {
  tableState.showTable = !tableState.showTable;
}

/**
 * 数据列表导出
 */
function fnRecordExport() {
  Modal.confirm({
    title: 'Tip',
    content: t('views.perfManage.goldTarget.exportSure'),
    onOk() {
      const key = 'exportKPI';
      message.loading({ content: t('common.loading'), key });

      if (tableState.data.length <= 0) {
        message.error({
          content: t('views.perfManage.goldTarget.exportEmpty'),
          key,
          duration: 2,
        });
        return;
      }

      const tableColumnsTitleArr: string[] = [];
      const tableColumnsKeyArr: string[] = [];
      for (const columns of tableColumnsDnd.value) {
        tableColumnsTitleArr.push(`${columns.title}`);
        tableColumnsKeyArr.push(`${columns.key}`);
      }

      const kpiDataArr = [];
      for (const item of tableState.data) {
        const kpiData: Record<string, any> = {};
        const keys = Object.keys(item);
        for (let i = 0; i <= tableColumnsKeyArr.length; i++) {
          for (const key of keys) {
            if (tableColumnsKeyArr[i] === key) {
              const title = tableColumnsTitleArr[i];
              kpiData[title] = item[key];
            }
          }
        }
        kpiDataArr.push(kpiData);
      }

      writeSheet(kpiDataArr, 'KPI', { header: tableColumnsTitleArr })
        .then(fileBlob => saveAs(fileBlob, `kpi_data_${Date.now()}.xlsx`))
        .finally(() => {
          message.success({
            content: t('common.msgSuccess', { msg: t('common.export') }),
            key,
            duration: 2,
          });
        });
    },
  });
}

/**查询数据列表表头 */
function fnGetListTitle() {
  // 当前语言
  var language = currentLocale.value.split('_')[0];
  if (language === 'zh') language = 'cn';

  // 获取表头文字
  getKPITitle(state.neType[0])
    .then(res => {
      if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
        tableColumns.value = [];
        const columns: ColumnsType = [
          {
            title: t('views.perfManage.perfData.neName'),
            dataIndex: 'neName',
            key: 'neName',
            align: 'left',
            width: 100,
          },
        ];
        for (const item of res.data) {
          const kpiDisplay = item[`${language}Title`];
          const kpiValue = item[`kpiId`];
          columns.push({
            title: kpiDisplay,
            dataIndex: kpiValue,
            align: 'left',
            key: kpiValue,
            resizable: true,
            width: 100,
            minWidth: 150,
            maxWidth: 300,
          });
        }
        columns.push({
          title: t('views.perfManage.goldTarget.time'),
          dataIndex: 'timeGroup',
          align: 'left',
          fixed: 'right',
          key: 'timeGroup',
          sorter: true,
          width: 100,
        });
        nextTick(() => {
          tableColumns.value = columns;
        });
        return true;
      } else {
        message.warning({
          content: t('common.getInfoFail'),
          duration: 2,
        });
        return false;
      }
    })
    .then(result => {
      result && fnGetList();
    });
}

/**查询数据列表 */
function fnGetList() {
  if (tableState.loading) return;
  tableState.loading = true;
  queryParams.neType = state.neType[0];
  queryParams.neId = state.neType[1];
  queryParams.startTime = queryRangePicker.value[0];
  queryParams.endTime = queryRangePicker.value[1];
  listKPIData(toRaw(queryParams))
    .then(res => {
      tableState.loading = false;
      if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
        tablePagination.total = res.data.length;
        tableState.data = res.data;
        return true;
      }
      return false;
    })
    .then(result => {
      if (result) {
        if (kpiChart.value == null) {
          fnRanderChart();
        } else {
          fnRanderChartData();
        }
      }
    });
}

/**绘制图表 */
function fnRanderChart() {
  const container: HTMLElement | undefined = kpiChartDom.value;
  if (!container) return;
  kpiChart.value = markRaw(echarts.init(container, 'light'));

  fnRanderChartData();

  // 创建 ResizeObserver 实例
  var observer = new ResizeObserver(entries => {
    if (kpiChart.value) {
      kpiChart.value.resize();
    }
  });
  // 监听元素大小变化
  observer.observe(container);
}

/**图表数据渲染 */
function fnRanderChartData() {
  if (kpiChart.value == null && tableState.data.length <= 0) {
    return;
  }

  const xDatas: string[] = [];
  const yDatas: Record<string, any>[] = [];

  const tableColumnsKeyArr: string[] = [];

  const columnsLen = tableColumnsDnd.value.length;
  for (let i = 0; i < columnsLen; i++) {
    const columns = tableColumnsDnd.value[i];
    if (
      columns.key === 'neName' ||
      columns.key === 'startIndex' ||
      columns.key === 'timeGroup'
    ) {
      continue;
    }
    const color = generateColorRGBA();
    yDatas.push({
      name: `${columns.title}`,
      type: 'line',
      symbol: 'none',
      sampling: 'lttb',
      itemStyle: {
        color: color,
      },
      areaStyle: {
        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
          {
            offset: 0,
            color: color.replace(')', ',0.8)'),
          },
          {
            offset: 1,
            color: color.replace(')', ',0.3)'),
          },
        ]),
      },
      data: [],
    });
    tableColumnsKeyArr.push(`${columns.key}`);
  }

  // 用降序就反转
  let orgData = tableState.data;
  if (queryParams.sortOrder === 'desc') {
    orgData = orgData.toReversed();
  }
  for (const item of orgData) {
    xDatas.push(item['timeGroup']);
    const keys = Object.keys(item);
    for (let i = 0; i < tableColumnsKeyArr.length; i++) {
      for (const key of keys) {
        if (tableColumnsKeyArr[i] === key) {
          yDatas[i].data.push(+item[key]);
        }
      }
    }
  }
  // console.log(queryParams.sortOrder, xDatas, yDatas);

  const option: EChartsOption = {
    tooltip: {
      trigger: 'axis',
      position: function (pt: any) {
        return [pt[0], '10%'];
      },
    },
    xAxis: {
      type: 'category',
      boundaryGap: false,
      data: xDatas,
    },
    yAxis: {
      type: 'value',
      boundaryGap: [0, '100%'],
    },
    legend: {
      type: 'scroll',
      orient: 'vertical',
      top: 40,
      right: 20,
      itemWidth: 20,
      itemGap: 25,
      textStyle: {
        color: '#646A73',
      },
      icon: 'circle',
      selected: {
        // 选中'系列1'
        系列1: true,
        // 不选中'系列2'
        系列2: false,
      },
    },
    grid: {
      left: '10%',
      right: '30%',
      bottom: '20%',
    },
    dataZoom: [
      {
        type: 'inside',
        start: 90,
        end: 100,
      },
      {
        start: 90,
        end: 100,
      },
    ],
    series: yDatas,
  };
  kpiChart.value.setOption(option);
}

onMounted(() => {
  // 获取网元网元列表
  neInfoStore.fnNelist().then(res => {
    if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
      if (res.data.length > 0) {
        // 过滤不可用的网元
        neCascaderOptions.value = neInfoStore.getNeCascaderOptions.filter(
          (item: any) => {
            return !['OMC'].includes(item.value);
          }
        );
        if (neCascaderOptions.value.length === 0) {
          message.warning({
            content: t('common.noData'),
            duration: 2,
          });
          return;
        }
        // 默认选择UPF
        const item = neCascaderOptions.value.find(s => s.value === 'UPF');
        if (item && item.children) {
          const info = item.children[0];
          state.neType = [info.neType, info.neId];
          queryParams.neType = info.neType;
          queryParams.neId = info.neId;
        } else {
          const info = neCascaderOptions.value[0].children[0];
          state.neType = [info.neType, info.neId];
          queryParams.neType = info.neType;
          queryParams.neId = info.neId;
        }

        // 查询当前小时
        const nowDate: Date = new Date();
        nowDate.setMinutes(0, 0, 0);
        queryRangePicker.value[0] = '2024-01-30 00:00:00'; // parseDateToStr(nowDate);
        nowDate.setMinutes(59, 59, 59);
        queryRangePicker.value[1] = parseDateToStr(nowDate);
        fnGetListTitle();
      }
    } else {
      message.warning({
        content: t('common.noData'),
        duration: 2,
      });
    }
  });
});
</script>

<template>
  <PageContainer>
    <a-card
      v-show="tableState.seached"
      :bordered="false"
      :body-style="{ marginBottom: '24px', paddingBottom: 0 }"
    >
      <!-- 表格搜索栏 -->
      <a-form :model="queryParams" name="queryParamsFrom" layout="horizontal">
        <a-row :gutter="16">
          <a-col :lg="6" :md="12" :xs="24">
            <a-form-item
              name="neType"
              :label="t('views.traceManage.task.neType')"
            >
              <a-cascader
                v-model:value="state.neType"
                :options="neCascaderOptions"
                :allow-clear="false"
                :placeholder="t('common.selectPlease')"
              />
            </a-form-item>
          </a-col>
          <a-col :lg="10" :md="12" :xs="24">
            <a-form-item
              :label="t('views.perfManage.goldTarget.timeFrame')"
              name="eventTime"
            >
              <a-range-picker
                v-model:value="queryRangePicker"
                value-format="YYYY-MM-DD HH:mm:ss"
                format="YYYY-MM-DD HH:mm:ss"
                :allow-clear="false"
                show-time
              />
            </a-form-item>
          </a-col>
          <a-col :lg="4" :md="12" :xs="24">
            <a-form-item
              :label="t('views.perfManage.goldTarget.interval')"
              name="interval"
            >
              <a-select
                v-model:value="queryParams.interval"
                :placeholder="t('common.selectPlease')"
                :options="[
                  { label: '5S', value: 5 },
                  { label: '1M', value: 60 },
                  { label: '5M', value: 300 },
                  { label: '15M', value: 900 },
                  { label: '30M', value: 1800 },
                  { label: '60M', value: 3600 },
                ]"
              />
            </a-form-item>
          </a-col>
          <a-col :lg="2" :md="12" :xs="24">
            <a-form-item>
              <a-space :size="8">
                <a-button type="primary" @click.prevent="fnGetListTitle()">
                  <template #icon><SearchOutlined /></template>
                  {{ t('common.search') }}
                </a-button>
              </a-space>
            </a-form-item>
          </a-col>
        </a-row>
      </a-form>
    </a-card>

    <a-card :bordered="false" :body-style="{ padding: '0px' }">
      <!-- 插槽-卡片左侧侧 -->
      <template #title>
        <a-space :size="8" align="center">
          <a-button
            type="primary"
            :loading="tableState.loading"
            @click.prevent="fnChangShowType()"
          >
            <template #icon> <AreaChartOutlined /> </template>
            {{
              tableState.showTable
                ? t('views.perfManage.goldTarget.kpiChartTitle')
                : t('views.perfManage.goldTarget.kpiTableTitle')
            }}
          </a-button>
          <a-button
            type="dashed"
            @click.prevent="fnRecordExport()"
            v-show="tableState.showTable"
          >
            <template #icon>
              <ExportOutlined />
            </template>
            {{ t('common.export') }}
          </a-button>
        </a-space>
      </template>

      <!-- 插槽-卡片右侧 -->
      <template #extra>
        <a-space :size="8" align="center" v-show="tableState.showTable">
          <a-tooltip>
            <template #title>{{ t('common.searchBarText') }}</template>
            <a-switch
              v-model:checked="tableState.seached"
              :checked-children="t('common.switch.show')"
              :un-checked-children="t('common.switch.hide')"
              size="small"
            />
          </a-tooltip>
          <a-tooltip>
            <template #title>{{ t('common.reloadText') }}</template>
            <a-button type="text" @click.prevent="fnGetList()">
              <template #icon><ReloadOutlined /></template>
            </a-button>
          </a-tooltip>
          <TableColumnsDnd
            v-if="tableColumns.length > 0"
            :columns="tableColumns"
            v-model:columns-dnd="tableColumnsDnd"
          ></TableColumnsDnd>
          <a-tooltip>
            <template #title>{{ t('common.sizeText') }}</template>
            <a-dropdown trigger="click" placement="bottomRight">
              <a-button type="text">
                <template #icon><ColumnHeightOutlined /></template>
              </a-button>
              <template #overlay>
                <a-menu
                  :selected-keys="[tableState.size as string]"
                  @click="fnTableSize"
                >
                  <a-menu-item key="default">
                    {{ t('common.size.default') }}
                  </a-menu-item>
                  <a-menu-item key="middle">
                    {{ t('common.size.middle') }}
                  </a-menu-item>
                  <a-menu-item key="small">
                    {{ t('common.size.small') }}
                  </a-menu-item>
                </a-menu>
              </template>
            </a-dropdown>
          </a-tooltip>
        </a-space>
      </template>

      <!-- 表格列表 -->
      <a-table
        v-show="tableState.showTable"
        class="table"
        row-key="id"
        :columns="tableColumnsDnd"
        :loading="tableState.loading"
        :data-source="tableState.data"
        :size="tableState.size"
        :pagination="tablePagination"
        :scroll="{ x: tableColumnsDnd.length * 200, y: 450 }"
        @resizeColumn="(w:number, col:any) => (col.width = w)"
        :show-expand-column="false"
        @change="fnTableChange"
      >
      </a-table>

      <!-- 图表 -->
      <div style="padding: 24px" v-show="!tableState.showTable">
        <div ref="kpiChartDom" style="height: 450px; width: 100%"></div>
      </div>
    </a-card>
  </PageContainer>
</template>

<style lang="less" scoped></style>
