<script lang="ts" setup>
import { onMounted, reactive } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { message, Modal } from 'ant-design-vue/lib';
import { ColumnsType } from 'ant-design-vue/lib/table';
import { PageContainer } from 'antdv-pro-layout';
import { dumpStart, dumpStop, dumpDownload, traceUPF } from '@/api/trace/pcap';
import { listAllNeInfo } from '@/api/ne/neInfo';
import { getNeFile } from '@/api/tool/neFile';
import saveAs from 'file-saver';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import useI18n from '@/hooks/useI18n';
import { MENU_PATH_INLINE } from '@/constants/menu-constants';
const router = useRouter();
const route = useRoute();
const { t } = useI18n();

/**对话框对象信息状态类型 */
type ModalStateType = {
  /**表单数据 */
  from: Record<
    string,
    {
      loading: boolean;
      /**网元名 */
      title: string;
      /**命令 */
      cmdStart: string;
      /**upf标准版需要停止命令，一般空字符 */
      cmdStop: string;
      /**任务编号 */
      taskCode: string;
      /**任务日志,upf标准版为空字符串 */
      logMsg: string;
      /**提交表单参数 */
      data: {
        neType: string;
        neId: string;
        cmd?: string;
      };
    }
  >;
  /**tcpdump命令组 */
  cmdOptions: {
    /**命令名称 */
    label: string;
    /**命令选中值 */
    value: string;
    /**开始命令 */
    start: string;
    /**停止命令 */
    stop: string;
  }[];
  /**UPF命令组 */
  cmdOptionsUPF: {
    /**命令名称 */
    label: string;
    /**命令选中值 */
    value: string;
    /**开始命令 */
    start: string;
    /**停止命令 */
    stop: string;
  }[];
  /**详情框是否显示 */
  visibleByView: boolean;
  /**详情框内容 */
  logMsg: string;
};

/**对话框对象信息状态 */
let modalState: ModalStateType = reactive({
  from: {},
  cmdOptions: [
    {
      label: t('views.traceManage.pcap.execCmd'),
      value: 'any',
      start: '-n -v -s 0',
      stop: '',
    },
    {
      label: t('views.traceManage.pcap.execCmd2'),
      value: 'any2',
      start: 'sctp or tcp port 3030 or 8088',
      stop: '',
    },
    {
      label: t('views.traceManage.pcap.execCmd3'),
      value: 'any3',
      start: '-n -s 0 -v -G 10 -W 7',
      stop: '',
    },
  ],
  cmdOptionsUPF: [
    {
      label: t('views.traceManage.pcap.execUPFCmdA'),
      value: 'pcap trace',
      start: 'pcap trace rx tx max 100000 intfc any',
      stop: 'pcap trace rx tx off',
    },
    {
      label: t('views.traceManage.pcap.execUPFCmdB'),
      value: 'pcap dispatch',
      start: 'pcap dispatch trace on max 100000',
      stop: 'pcap dispatch trace off',
    },
  ],
  visibleByView: false,
  logMsg: '',
});

/**表格状态类型 */
type TabeStateType = {
  /**加载等待 */
  loading: boolean;
  /**记录数据 */
  data: object[];
  /**勾选记录 */
  selectedRowKeys: (string | number)[];
};

/**表格状态 */
let tableState: TabeStateType = reactive({
  loading: false,
  data: [],
  selectedRowKeys: [],
});

/**表格字段列 */
let tableColumns: ColumnsType = [
  {
    title: t('views.ne.common.neType'),
    dataIndex: 'neType',
    align: 'left',
    width: 100,
  },
  {
    title: t('views.ne.common.neId'),
    dataIndex: 'neId',
    align: 'left',
    width: 100,
  },
  {
    title: t('views.ne.common.neName'),
    dataIndex: 'neName',
    align: 'left',
    width: 100,
  },
  {
    title: t('views.ne.common.ipAddr'),
    dataIndex: 'ip',
    align: 'left',
    width: 150,
  },
  {
    title: t('views.traceManage.pcap.cmd'),
    key: 'cmd',
    dataIndex: 'serverState',
    align: 'left',
    width: 350,
  },
  {
    title: t('common.operate'),
    key: 'id',
    align: 'left',
  },
];

/**表格多选 */
function fnTableSelectedRowKeys(keys: (string | number)[]) {
  tableState.selectedRowKeys = keys;
}

/**查询全部网元数据列表 */
function fnGetList() {
  if (tableState.loading) return;
  tableState.loading = true;
  listAllNeInfo({
    bandStatus: false,
  }).then(res => {
    if (
      res.code === RESULT_CODE_SUCCESS &&
      Array.isArray(res.data) &&
      res.data.length > 0
    ) {
      tableState.data = res.data;
      // 初始网元参数表单
      if (tableState.data.length > 0) {
        const { start, stop } = modalState.cmdOptions[0];
        for (const item of res.data) {
          modalState.from[item.id] = {
            loading: false,
            title: item.neName,
            cmdStart: start,
            cmdStop: stop,
            taskCode: '',
            logMsg: '',
            data: {
              neType: item.neType,
              neId: item.neId,
            },
          };
        }
      }
    } else {
      message.warning({
        content: t('common.noData'),
        duration: 2,
      });
    }
    tableState.loading = false;
  });
}

/**抓包命令选择 */
function fnSelectCmd(id: any, option: any) {
  modalState.from[id].cmdStart = option.start;
  modalState.from[id].cmdStop = option.stop;
  // 重置任务
  modalState.from[id].taskCode = '';
  modalState.from[id].logMsg = '';
}

/**
 * 开始
 * @param row 行记录
 */
function fnRecordStart(row?: Record<string, any>) {
  let neIDs: string[] = [];
  if (row) {
    neIDs = [`${row.id}`];
  } else {
    row = {
      neName: t('views.traceManage.pcap.textSelect'),
    };
    neIDs = tableState.selectedRowKeys.map(s => `${s}`);
  }

  Modal.confirm({
    title: t('common.tipTitle'),
    content: t('views.traceManage.pcap.startTip', { title: row.neName }),
    onOk() {
      const hide = message.loading(t('common.loading'), 0);
      const fromArr = neIDs.map(id => modalState.from[id]);
      const reqArr = fromArr.map(from => {
        const data = Object.assign({ cmd: from.cmdStart }, from.data);
        if (from.data.neType === 'UPF' && from.cmdStart.startsWith('pcap')) {
          return traceUPF(data);
        }
        return dumpStart(data);
      });
      Promise.allSettled(reqArr)
        .then(resArr => {
          resArr.forEach((res, idx) => {
            const title = fromArr[idx].title;
            if (res.status === 'fulfilled') {
              const resV = res.value;
              if (resV.code === RESULT_CODE_SUCCESS) {
                if (!fromArr[idx].cmdStop) {
                  fromArr[idx].taskCode = resV.data;
                }
                fromArr[idx].loading = true;
                message.success({
                  content: t('views.traceManage.pcap.startOk', { title }),
                  duration: 3,
                });
              } else {
                message.warning({
                  content: `${resV.msg}`,
                  duration: 3,
                });
              }
            } else {
              message.error({
                content: t('views.traceManage.pcap.startErr', { title }),
                duration: 3,
              });
            }
          });
        })
        .finally(() => {
          hide();
        });
    },
  });
}

/**
 * 停止
 * @param row 行记录
 */
function fnRecordStop(row?: Record<string, any>) {
  let neIDs: string[] = [];
  if (row) {
    neIDs = [`${row.id}`];
  } else {
    row = {
      neName: t('views.traceManage.pcap.textSelect'),
    };
    neIDs = tableState.selectedRowKeys.map(s => `${s}`);
  }

  Modal.confirm({
    title: t('common.tipTitle'),
    content: t('views.traceManage.pcap.stopTip', { title: row.neName }),
    onOk() {
      const fromArr = neIDs.map(id => modalState.from[id]);
      const reqArr: any = [];
      for (const from of fromArr) {
        if (from.data.neType === 'UPF' && from.cmdStart.startsWith('pcap')) {
          reqArr.push(
            traceUPF(Object.assign({ cmd: from.cmdStop }, from.data))
          );
        } else {
          const taskCode = from.taskCode;
          if (!taskCode) {
            message.warning({
              content: t('views.traceManage.pcap.stopNotRun', {
                title: from.title,
              }),
              duration: 3,
            });
            continue;
          }
          reqArr.push(
            dumpStop(Object.assign({ taskCode: from.taskCode }, from.data))
          );
        }
      }
      if (reqArr.length === 0) return;

      const hide = message.loading(t('common.loading'), 0);
      Promise.allSettled(reqArr)
        .then(resArr => {
          resArr.forEach((res, idx) => {
            const title = fromArr[idx].title;

            if (res.status === 'fulfilled') {
              const resV = res.value;
              fromArr[idx].loading = false;
              fromArr[idx].logMsg = '';
              if (fromArr[idx].cmdStop) {
                fromArr[idx].taskCode = '';
              }

              if (resV.code === RESULT_CODE_SUCCESS) {
                if (fromArr[idx].cmdStop) {
                  fromArr[idx].taskCode = resV.data;
                } else {
                  fromArr[idx].logMsg = resV.msg;
                }
                message.success({
                  content: t('views.traceManage.pcap.stopOk', { title }),
                  duration: 3,
                });
              } else if (resV.msg.indexOf('not run') > 0) {
                message.warning({
                  content: t('views.traceManage.pcap.stopNotRun', { title }),
                  duration: 3,
                });
              } else {
                message.warning({
                  content: `${resV.msg}`,
                  duration: 3,
                });
              }
            } else {
              message.error({
                content: t('views.traceManage.pcap.stopErr', { title }),
                duration: 3,
              });
            }
          });
        })
        .finally(() => {
          hide();
        });
    },
  });
}

/**下载PCAP文件 */
function fnDownPCAP(row?: Record<string, any>) {
  let neIDs: string[] = [];
  if (row) {
    neIDs = [`${row.id}`];
  } else {
    row = {
      neName: t('views.traceManage.pcap.textSelect'),
    };
    neIDs = tableState.selectedRowKeys.map(s => `${s}`);
  }

  Modal.confirm({
    title: t('common.tipTitle'),
    content: t('views.traceManage.pcap.downTip', { title: row.neName }),
    onOk() {
      const fromArr = neIDs.map(id => modalState.from[id]);
      const reqArr: any = [];
      for (const from of fromArr) {
        const taskCode = from.taskCode;
        if (!taskCode) {
          message.warning({
            content: t('views.traceManage.pcap.stopNotRun', {
              title: from.title,
            }),
            duration: 3,
          });
          continue;
        }
        if (from.data.neType === 'UPF' && taskCode.startsWith('/tmp')) {
          const fileName = taskCode.substring(taskCode.lastIndexOf('/') + 1);
          reqArr.push(
            getNeFile(
              Object.assign(
                { path: '/tmp', fileName, delTemp: true },
                from.data
              )
            )
          );
        } else {
          reqArr.push(
            dumpDownload(
              Object.assign({ taskCode: taskCode, delTemp: true }, from.data)
            )
          );
        }
      }
      if (reqArr.length === 0) return;

      const hide = message.loading(t('common.loading'), 0);
      Promise.allSettled(reqArr)
        .then(resArr => {
          resArr.forEach((res, idx) => {
            const title = fromArr[idx].title;
            const taskCode = fromArr[idx].taskCode;

            if (res.status === 'fulfilled') {
              const resV = res.value;
              if (resV.code === RESULT_CODE_SUCCESS) {
                message.success({
                  content: t('views.traceManage.pcap.downOk', { title }),
                  duration: 3,
                });
                // 文件名
                if (taskCode.startsWith('/tmp')) {
                  saveAs(resV.data, `${title}_${Date.now()}.pcap`);
                } else {
                  saveAs(resV.data, `${title}_${Date.now()}.zip`);
                }
              } else {
                message.warning({
                  content: `${resV.msg}`,
                  duration: 3,
                });
              }
            } else {
              message.error({
                content: t('views.traceManage.pcap.downErr', { title }),
                duration: 3,
              });
            }
          });
        })
        .finally(() => {
          hide();
        });
    },
  });
}

/**批量操作 */
function fnBatchOper(key: string) {
  switch (key) {
    case 'start':
      fnRecordStart();
      break;
    case 'stop':
      fnRecordStop();
      break;
    case 'down':
      fnDownPCAP();
      break;
    default:
      console.warn('undefined batch oper', key);
      break;
  }
}

/**
 * 对话框弹出显示为 查看
 * @param dictId 编号id
 */
function fnModalVisibleByVive(id: string | number) {
  const from = modalState.from[id];
  if (!from) return;
  modalState.visibleByView = true;
  modalState.logMsg = from.logMsg;
}

/**
 * 对话框弹出关闭执行函数
 * 进行表达规则校验
 */
function fnModalCancel() {
  modalState.visibleByView = false;
  modalState.logMsg = '';
}

/**跳转文件数据页面 */
function fnFileView(row?: Record<string, any>) {
  let query = undefined;
  if (row) {
    const from = modalState.from[row.id];
    query = {
      neId: from.data.neId,
      neType: from.data.neType,
    };
  }
  router.push({
    path: `${route.path}${MENU_PATH_INLINE}/file`,
    query: query,
  });
}

onMounted(() => {
  // 获取网元列表
  fnGetList();
});
</script>

<template>
  <PageContainer>
    <a-card :bordered="false" :body-style="{ padding: '0px' }">
      <!-- 插槽-卡片左侧侧 -->
      <template #title>
        <a-space :size="8" align="center">
          <a-button @click="fnFileView()">
            <FileSearchOutlined />
            {{ t('views.traceManage.pcap.fileView') }}
          </a-button>

          <a-dropdown trigger="click">
            <a-button :disabled="tableState.selectedRowKeys.length <= 0">
              {{ t('views.traceManage.pcap.batchOper') }}
              <DownOutlined />
            </a-button>
            <template #overlay>
              <a-menu @click="({ key }:any) => fnBatchOper(key)">
                <a-menu-item key="start">
                  <PlayCircleOutlined />
                  {{ t('views.traceManage.pcap.batchStartText') }}
                </a-menu-item>
                <a-menu-item key="stop">
                  <StopOutlined />
                  {{ t('views.traceManage.pcap.batchStopText') }}
                </a-menu-item>
                <a-menu-item key="down">
                  <DownloadOutlined />
                  {{ t('views.traceManage.pcap.batchDownText') }}
                </a-menu-item>
              </a-menu>
            </template>
          </a-dropdown>
        </a-space>
      </template>

      <!-- 插槽-卡片右侧 -->
      <template #extra>
        <a-space :size="8" align="center">
          <a-tooltip>
            <template #title>{{ t('common.reloadText') }}</template>
            <a-button type="text" @click.prevent="fnGetList()">
              <template #icon><ReloadOutlined /></template>
            </a-button>
          </a-tooltip>
        </a-space>
      </template>

      <!-- 表格列表 -->
      <a-table
        class="table"
        row-key="id"
        size="small"
        :columns="tableColumns"
        :loading="tableState.loading"
        :data-source="tableState.data"
        :pagination="false"
        :scroll="{ x: tableColumns.length * 170 }"
        :row-selection="{
          type: 'checkbox',
          selectedRowKeys: tableState.selectedRowKeys,
          onChange: fnTableSelectedRowKeys,
        }"
      >
        <template #bodyCell="{ column, record }">
          <template v-if="column.key === 'cmd'">
            <a-auto-complete
              v-model:value="modalState.from[record.id].cmdStart"
              :options="
                record.neType === 'UPF'
                  ? modalState.cmdOptions.concat(modalState.cmdOptionsUPF)
                  : modalState.cmdOptions
              "
              :placeholder="t('views.traceManage.pcap.capArgPlease')"
              :disabled="modalState.from[record.id].loading"
              allow-clear
              @select="(_: any, option: any) => fnSelectCmd(record.id, option)"
              style="width: 100%"
            />
          </template>
          <template v-if="column.key === 'id'">
            <a-space :size="8" align="start" direction="horizontal">
              <a-tooltip placement="topRight">
                <template #title>
                  <div>{{ t('views.traceManage.pcap.textStart') }}</div>
                </template>
                <a-button
                  type="primary"
                  size="small"
                  :disabled="modalState.from[record.id].loading"
                  @click.prevent="fnRecordStart(record)"
                >
                  <template #icon><PlayCircleOutlined /> </template>
                </a-button>
              </a-tooltip>
              <a-tooltip
                placement="topRight"
                v-if="
                  modalState.from[record.id].loading ||
                  modalState.from[record.id].cmdStop
                "
              >
                <template #title>
                  <div>{{ t('views.traceManage.pcap.textStop') }}</div>
                </template>
                <a-button
                  type="default"
                  danger
                  size="small"
                  @click.prevent="fnRecordStop(record)"
                >
                  <template #icon><StopOutlined /> </template>
                </a-button>
              </a-tooltip>

              <a-tooltip
                placement="topRight"
                v-if="
                  !modalState.from[record.id].loading &&
                  !!modalState.from[record.id].logMsg
                "
              >
                <template #title>
                  <div>{{ t('views.traceManage.pcap.textLog') }}</div>
                </template>
                <a-button
                  type="primary"
                  ghost
                  size="small"
                  @click.prevent="fnModalVisibleByVive(record.id)"
                >
                  <template #icon><FileTextOutlined /> </template>
                </a-button>
              </a-tooltip>
              <a-tooltip
                placement="topRight"
                v-if="
                  !modalState.from[record.id].loading &&
                  !!modalState.from[record.id].taskCode
                "
              >
                <template #title>
                  <div>{{ t('views.traceManage.pcap.textDown') }}</div>
                </template>
                <a-button
                  type="primary"
                  ghost
                  size="small"
                  @click.prevent="fnDownPCAP(record)"
                >
                  <template #icon><DownloadOutlined /> </template>
                </a-button>
              </a-tooltip>
            </a-space>
          </template>
        </template>
      </a-table>
    </a-card>

    <!-- 日志信息框 -->
    <ProModal
      :drag="true"
      :width="800"
      :visible="modalState.visibleByView"
      :footer="false"
      :maskClosable="false"
      :keyboard="false"
      :body-style="{ padding: '12px' }"
      :title="t('views.traceManage.pcap.textLogMsg')"
      @cancel="fnModalCancel"
    >
      <a-textarea
        v-model:value="modalState.logMsg"
        :auto-size="{ minRows: 2, maxRows: 18 }"
        :disabled="true"
        style="color: rgba(0, 0, 0, 0.85)"
      />
    </ProModal>
  </PageContainer>
</template>

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