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

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

import { reactive, onMounted, toRaw, onBeforeUnmount, ref } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import { OptionsType, WS } from '@/plugins/ws-websocket';
import useI18n from '@/hooks/useI18n';
import { listSMFDataCDR } from '@/api/neData/smf';
import {
  RESULT_CODE_ERROR,
  RESULT_CODE_SUCCESS,
} from '@/constants/result-constants';
import { parseSizeFromByte } from '@/utils/parse-utils';
import { message } from 'ant-design-vue';
import useNeInfoStore from '@/store/modules/neinfo';
import dayjs, { Dayjs } from 'dayjs';
const { t, currentLocale } = useI18n();
const ws = new WS();

/**图DOM节点实例对象 */
const cdrChartDom = ref<HTMLElement | undefined>(undefined);
/**图实例对象 */
let cdrChart: echarts.ECharts | null = null;
/**图表配置 */
const option = {
  title: {
    text: 'Data Usage Report',
    left: 'left',
  },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      animation: true,
    },
    formatter: (params: any) => {
      const title = params[0].name;
      let uplinkValue = 0;
      let downlinkValue = 0;
      if (params[0].seriesName === 'Uplink') {
        uplinkValue = params[0].value;
      } else {
        downlinkValue = params[0].value;
      }
      if (params[1].seriesName === 'Uplink') {
        uplinkValue = params[1].value;
      } else {
        downlinkValue = params[1].value;
      }
      const uplinkValueF = parseSizeFromByte(uplinkValue);
      const downlinkValueF = parseSizeFromByte(downlinkValue);
      return `
      <div style="font-weight: bold;">${title}</div>
      <div>Downlink: ${downlinkValueF}</div>
      <div>Uplink: ${uplinkValueF}</div>
      `;
    },
  },
  toolbox: {
    feature: {
      dataZoom: {
        yAxisIndex: 'none',
      },
      saveAsImage: {},
    },
  },
  axisPointer: {
    link: [
      {
        xAxisIndex: 'all',
      },
    ],
  },
  dataZoom: [
    {
      show: false,
      realtime: true,
      start: 0,
      end: 100,
      xAxisIndex: [0, 1],
    },
    {
      type: 'inside',
      realtime: true,
      start: 0,
      end: 100,
      xAxisIndex: [0, 1],
    },
  ],
  grid: [
    {
      left: '10%',
      right: 50,
      height: '40%',
    },
    {
      left: '10%',
      right: 50,
      top: '50%',
      height: '40%',
    },
  ],
  xAxis: [
    {
      type: 'category',
      boundaryGap: false,
      axisLine: { onZero: true },
      data: [], // x轴初始数据
      axisLabel: {
        show: false, // 显示标签
        rotate: 15, // 设置倾斜角度（如15度）
      },
    },
    {
      gridIndex: 1,
      type: 'category',
      boundaryGap: false,
      axisLine: { onZero: true },
      data: [], // x轴初始数据
      axisLabel: {
        show: false, // 隐藏第二个 x 轴的标签
      },
      position: 'top',
    },
  ],
  yAxis: [
    {
      name: 'Downlink (Byte)',
      type: 'value',
    },
    {
      gridIndex: 1,
      name: 'Uplink (Byte)',
      type: 'value',
      inverse: true,
    },
  ],
  series: [
    {
      name: 'Downlink',
      type: 'line',
      data: [], // y轴初始数据
      symbol: 'circle', // 数据点形状
      symbolSize: 6, // 数据点大小
      smooth: true, // 平滑曲线
      color: 'rgb(0, 190, 99)',
      areaStyle: {
        color: {
          colorStops: [
            { offset: 0, color: 'rgba(0, 190, 99, .5)' },
            { offset: 1, color: 'rgba(0, 190, 99, 0.5)' },
          ],
          x: 0,
          y: 0,
          x2: 0,
          y2: 1,
          type: 'linear',
          global: false,
        },
        shadowColor: 'rgba(0, 0, 0, 0.1)',
        shadowBlur: 10,
      },
    },
    {
      name: 'Uplink',
      type: 'line',
      xAxisIndex: 1,
      yAxisIndex: 1,
      data: [], // y轴初始数据
      symbol: 'circle', // 数据点形状
      symbolSize: 6, // 数据点大小
      smooth: true, // 平滑曲线
      color: 'rgb(17, 178, 255)',
      areaStyle: {
        color: {
          colorStops: [
            { offset: 0, color: 'rgba(17, 178, 255, .5)' },
            { offset: 1, color: 'rgba(17, 178, 255, 0.5)' },
          ],
          x: 0,
          y: 0,
          x2: 0,
          y2: 1,
          type: 'linear',
          global: false,
        },
        shadowColor: 'rgba(0, 0, 0, 0.1)',
        shadowBlur: 10,
      },
    },
  ],
};
/**绘制图表 */
function fnRanderChart() {
  const container: HTMLElement | undefined = cdrChartDom.value;
  if (!container) return;
  const locale = currentLocale.value.split('_')[0];
  cdrChart = echarts.init(container, 'light', {
    // https://github.com/apache/echarts/tree/release/src/i18n 取值langEN.ts ==> EN
    locale: locale.toUpperCase(),
  });
  cdrChart.setOption(option);
  // cdrChart.showLoading('default', {
  //   text: 'Please enter IMSI to query user traffic',
  //   fontSize: 16, // 字体大小
  // });

  // 创建 ResizeObserver 实例 监听图表容器大小变化，并在变化时调整图表大小
  var observer = new ResizeObserver(entries => {
    if (cdrChart && !cdrChart.isDisposed) {
      cdrChart.resize();
    }
  });
  // 监听元素大小变化
  observer.observe(container);
}

/**网元可选 */
let neOtions = ref<Record<string, any>[]>([]);

/**开始结束时间 */
let queryRangePicker = ref<[Dayjs, Dayjs] | undefined>([
  dayjs().startOf('hour'),
  dayjs().endOf('hour'),
]);
/**时间范围 */
let rangePickerPresets = ref([
  {
    label: 'Now hour',
    value: [dayjs().startOf('hour'), dayjs().endOf('hour')],
  },
  { label: 'Today', value: [dayjs().startOf('day'), dayjs().endOf('day')] },
  {
    label: 'Yesterday',
    value: [
      dayjs().subtract(1, 'day').startOf('day'),
      dayjs().subtract(1, 'day').endOf('day'),
    ],
  },
]);

/**查询参数 */
let queryParams = reactive({
  /**网元类型 */
  neType: 'SMF',
  neId: '001',
  subscriberID: '',
  dnn: '',
  sortField: 'timestamp',
  sortOrder: 'desc',
  /**开始时间 */
  beginTime: undefined as undefined | number,
  /**结束时间 */
  endTime: undefined as undefined | number,
  /**当前页数 */
  pageNum: 1,
  /**每页条数 */
  pageSize: 1000,
});

/**查询参数重置 */
function fnQueryReset() {
  queryParams.subscriberID = '';
  queryParams.dnn = '';
  queryRangePicker.value = [dayjs().startOf('hour'), dayjs().endOf('hour')];
  fnGetList(1);
}

let state = reactive({
  /**表格数据 */
  data: [] as any[],
  /**表格总数 */
  total: 0,
  /**表格加载状态 */
  loading: false,
  /**数据总量 up,down */
  dataUsage: ['0 B', '0 B'],
});

/**查询列表, pageNum初始页数 */
function fnGetList(pageNum?: number) {
  if (state.loading) return;
  state.loading = true;
  if (!queryParams.subscriberID) {
    message.warning('Please enter IMSI to query user traffic');
    state.loading = false;
    return;
  }
  if (pageNum) {
    queryParams.pageNum = pageNum;
  }
  if (cdrChart) {
    cdrChart.showLoading('default', {
      text: 'Loading...',
      fontSize: 16, // 字体大小
    });
  }

  // 时间范围
  if (
    Array.isArray(queryRangePicker.value) &&
    queryRangePicker.value.length > 0
  ) {
    queryParams.beginTime = queryRangePicker.value[0].valueOf();
    queryParams.endTime = queryRangePicker.value[1].valueOf();
  } else {
    queryParams.beginTime = undefined;
    queryParams.endTime = undefined;
  }

  listSMFDataCDR(toRaw(queryParams))
    .then(res => {
      if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data.rows)) {
        const { total, rows } = res.data;
        state.total = total;
        // 遍历处理cdr字符串数据
        state.data = rows
          .map((item: any) => {
            let cdrJSON = item.cdrJSON;
            if (!cdrJSON) {
              Reflect.set(item, 'cdrJSON', {});
            }

            try {
              cdrJSON = JSON.parse(cdrJSON);
              Reflect.set(item, 'cdrJSON', cdrJSON);
            } catch (error) {
              console.error(error);
              Reflect.set(item, 'cdrJSON', {});
            }

            return item;
          })
          .reverse();
      }
    })
    .finally(() => {
      state.loading = false;
      fnRanderChartDataLoad();
    });
}

/**图表配置数据x轴 */
let dataTimeXAxisData: string[] = [];
/**图表配置数据y轴 */
let dataVolumeUplinkYSeriesData: number[] = [];
let dataVolumeDownlinkYSeriesData: number[] = [];
/**图表数据渲染 */
function fnRanderChartDataLoad() {
  if (!cdrChart) return;
  dataTimeXAxisData = [];
  dataVolumeUplinkYSeriesData = [];
  dataVolumeDownlinkYSeriesData = [];
  if (state.data.length > 0) {
    // 处理数据渲染图表
    for (const item of state.data) {
      if (!item.cdrJSON.invocationTimestamp) {
        break;
      }
      // 时间
      const dataTime = item.cdrJSON.invocationTimestamp;
      const listOfMultipleUnitUsage = item.cdrJSON.listOfMultipleUnitUsage;
      if (
        !Array.isArray(listOfMultipleUnitUsage) ||
        listOfMultipleUnitUsage.length < 1
      ) {
        return 0;
      }
      // 数据
      let dataVolumeUplink = 0;
      let dataVolumeDownlink = 0;
      for (const v of listOfMultipleUnitUsage) {
        if (Array.isArray(v.usedUnitContainer)) {
          for (const used of v.usedUnitContainer) {
            dataVolumeUplink += +used.dataVolumeUplink;
            dataVolumeDownlink += +used.dataVolumeDownlink;
          }
        }
      }

      dataTimeXAxisData.push(dataTime);
      dataVolumeUplinkYSeriesData.push(dataVolumeUplink);
      dataVolumeDownlinkYSeriesData.push(dataVolumeDownlink);
    }
    // 绘制图数据
    fnRanderChartDataUpdate();
  } else {
    message.warning('No Data');
    cdrChart.hideLoading();
    cdrChart.setOption({
      title: {
        text: `Data Volume Uplink	/ Downlink By IMSI ${queryParams.subscriberID}`,
      },
      xAxis: [
        {
          data: dataTimeXAxisData,
        },
        {
          data: dataTimeXAxisData,
        },
      ],
      series: [
        {
          data: dataVolumeUplinkYSeriesData,
        },
        {
          data: dataVolumeDownlinkYSeriesData,
        },
      ],
    });
  }
}
/**图表数据渲染 */
function fnRanderChartDataUpdate() {
  if (cdrChart == null) return;
  // 绘制图数据
  cdrChart.setOption({
    title: {
      text: `Data Usage Report of IMSI ${queryParams.subscriberID}`,
    },
    xAxis: [
      {
        data: dataTimeXAxisData,
      },
      {
        data: dataTimeXAxisData,
      },
    ],
    series: [
      {
        data: dataVolumeUplinkYSeriesData,
      },
      {
        data: dataVolumeDownlinkYSeriesData,
      },
    ],
  });
  cdrChart.hideLoading();

  // 累加总量
  let uplinkTotal = 0;
  let downlinkTotal = 0;
  for (let index = 0; index < dataVolumeUplinkYSeriesData.length; index++) {
    uplinkTotal += dataVolumeUplinkYSeriesData[index];
    downlinkTotal += dataVolumeDownlinkYSeriesData[index];
  }
  state.dataUsage = [
    parseSizeFromByte(uplinkTotal),
    parseSizeFromByte(downlinkTotal),
  ];
}

/**
 * 实时数据
 */
function fnRealTime() {
  if (ws.state() === WebSocket.OPEN) {
    ws.close();
  }
  // 建立链接
  const options: OptionsType = {
    url: '/ws',
    params: {
      /**订阅通道组
       *
       * CDR会话事件-SMF (GroupID:1006)
       */
      subGroupID: `1006_${queryParams.neId}`,
    },
    onmessage: (res: Record<string, any>) => {
      const { code, requestId, data } = res;
      if (code === RESULT_CODE_ERROR) {
        console.warn(res.msg);
        return;
      }

      // 订阅组信息
      if (!data?.groupId) {
        return;
      }
      // cdrEvent CDR会话事件
      if (data.groupId === `1006_${queryParams.neId}`) {
        const cdrEvent = data.data;
        // 对应结束时间内
        if (queryParams.endTime) {
          const endTime = Math.round(queryParams.endTime / 1000);
          if (cdrEvent.timestamp > endTime) {
            return;
          }
        }
        const cdrJSON = cdrEvent.CDR;
        if (!cdrJSON.invocationTimestamp) {
          return;
        }
        // 对应IMSI
        if (
          cdrJSON.subscriberIdentifier.subscriptionIDData !==
          queryParams.subscriberID
        ) {
          return;
        }

        // 时间
        const dataTime = cdrJSON.invocationTimestamp;
        const listOfMultipleUnitUsage = cdrJSON.listOfMultipleUnitUsage;
        if (
          !Array.isArray(listOfMultipleUnitUsage) ||
          listOfMultipleUnitUsage.length < 1
        ) {
          return 0;
        }
        // 数据
        let dataVolumeUplink = 0;
        let dataVolumeDownlink = 0;
        for (const v of listOfMultipleUnitUsage) {
          if (Array.isArray(v.usedUnitContainer)) {
            for (const used of v.usedUnitContainer) {
              dataVolumeUplink += +used.dataVolumeUplink;
              dataVolumeDownlink += +used.dataVolumeDownlink;
            }
          }
        }
        // 添加数据
        dataTimeXAxisData.push(dataTime);
        dataVolumeUplinkYSeriesData.push(dataVolumeUplink);
        dataVolumeDownlinkYSeriesData.push(dataVolumeDownlink);
        fnRanderChartDataUpdate();
      }
    },
    onerror: (ev: any) => {
      console.error(ev);
    },
  };
  ws.connect(options);
}

onMounted(() => {
  // 获取网元网元列表
  useNeInfoStore()
    .fnNelist()
    .then(res => {
      if (res.code === RESULT_CODE_SUCCESS) {
        if (res.data.length > 0) {
          let arr: Record<string, any>[] = [];
          res.data.forEach((v: any) => {
            if (v.neType === 'SMF') {
              arr.push({ value: v.neId, label: v.neName });
            }
          });
          neOtions.value = arr;
          if (arr.length > 0) {
            queryParams.neId = arr[0].value;
          }
        }
      } else {
        message.warning({
          content: t('common.noData'),
          duration: 2,
        });
      }
    })
    .finally(() => {
      fnRanderChart();
      fnRealTime();
    });
});

onBeforeUnmount(() => {
  ws.close();
  if (cdrChart) {
    cdrChart.clear();
    cdrChart.dispose();
  }
});
</script>

<template>
  <PageContainer>
    <a-card
      :bordered="false"
      :body-style="{ marginBottom: '24px', paddingBottom: 0 }"
    >
      <!-- 表格搜索栏 -->
      <a-form :model="queryParams" name="queryParams" layout="horizontal">
        <a-row :gutter="16">
          <a-col :lg="6" :md="12" :xs="24">
            <a-form-item label="SMF" name="neId ">
              <a-select
                v-model:value="queryParams.neId"
                :options="neOtions"
                :placeholder="t('common.selectPlease')"
                @change="fnRealTime()"
                :disabled="state.loading"
              />
            </a-form-item>
          </a-col>
          <a-col :lg="6" :md="12" :xs="24">
            <a-form-item label="IMSI" name="subscriberID" :required="true">
              <a-input
                v-model:value="queryParams.subscriberID"
                allow-clear
                :placeholder="t('common.inputPlease')"
                :maxlength="40"
                :disabled="state.loading"
              ></a-input>
            </a-form-item>
          </a-col>
          <a-col :lg="6" :md="12" :xs="24">
            <a-form-item label="DNN" name="dnn">
              <a-input
                v-model:value="queryParams.dnn"
                allow-clear
                :placeholder="t('common.inputPlease')"
                :maxlength="40"
                :disabled="state.loading"
              ></a-input>
            </a-form-item>
          </a-col>
          <a-col :lg="4" :md="12" :xs="24">
            <a-form-item>
              <a-space :size="8">
                <a-button
                  type="primary"
                  @click.prevent="fnGetList(1)"
                  :loading="state.loading"
                >
                  <template #icon><SearchOutlined /></template>
                  {{ t('common.search') }}
                </a-button>
                <a-button
                  type="default"
                  @click.prevent="fnQueryReset"
                  :disabled="state.loading"
                >
                  <template #icon><ClearOutlined /></template>
                  {{ t('common.reset') }}
                </a-button>
              </a-space>
            </a-form-item>
          </a-col>
          <a-col :lg="8" :md="12" :xs="24">
            <a-form-item
              :label="t('views.dashboard.cdr.time')"
              name="queryRangePicker"
            >
              <a-range-picker
                v-model:value="queryRangePicker"
                :presets="rangePickerPresets"
                :bordered="true"
                :allow-clear="false"
                style="width: 100%"
                :show-time="{ format: 'HH:mm:ss' }"
                format="YYYY-MM-DD HH:mm:ss"
                :disabled="state.loading"
              ></a-range-picker>
            </a-form-item>
          </a-col>
        </a-row>
      </a-form>
    </a-card>

    <a-card :bordered="false">
      <!-- 图数据 -->
      <div ref="cdrChartDom" style="height: 600px; width: 100%"></div>

      <a-descriptions title="Data Usage" bordered :column="2">
        <a-descriptions-item label="Total Uplink">
          {{ state.dataUsage[0] }}
        </a-descriptions-item>
        <a-descriptions-item label="Total Downlink">
          {{ state.dataUsage[1] }}
        </a-descriptions-item>
      </a-descriptions>
    </a-card>
  </PageContainer>
</template>

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