<script setup lang="ts">
import { reactive, onMounted, onBeforeUnmount, ref } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import { message, Modal } from 'ant-design-vue/es';
import useI18n from '@/hooks/useI18n';
import {
  RESULT_CODE_ERROR,
  RESULT_CODE_SUCCESS,
} from '@/constants/result-constants';
import TerminalSSHView from '@/components/TerminalSSHView/index.vue';
import useNeInfoStore from '@/store/modules/neinfo';
import { iperfI, iperfV } from '@/api/tool/iperf';
const neInfoStore = useNeInfoStore();
const { t } = useI18n();

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

/**状态对象 */
let state = reactive({
  /**初始化 */
  initialized: false,
  /**运行中 */
  running: false,
  /**版本信息 */
  versionInfo: [],
  /**网元类型 */
  neType: [],
  /**数据类型 */
  dataType: 'options' as 'options' | 'command',
  /**ws参数 */
  params: {
    neType: '',
    neId: '',
    cols: 120,
    rows: 40,
  },
  /**ws数据 */
  data: {
    command: '', // 命令字符串
    version: 'V3', // 服务版本，默认V3
    mode: 'client', // 服务端或客户端，默认服务端
    // Server or Client
    port: 5201, // 服务端口
    interval: 1, // 每次报告之间的时间间隔，单位为秒
    // Server
    oneOff: false, // 只进行一次连接
    // Client
    host: '', // 客户端连接到的服务端IP地址
    udp: false, // use UDP rather than TCP
    time: 10, // 以秒为单位的传输时间（默认为 10 秒）
    reverse: false, // 以反向模式运行（服务器发送，客户端接收）
    window: '300k', // 设置窗口大小/套接字缓冲区大小
    parallel: 1, // 运行的并行客户端流数量
    bitrate: 0, // 以比特/秒为单位（0 表示无限制）
  },
});

/**连接发送 */
async function fnIPerf() {
  const [neType, neId] = state.neType;
  if (!neType || !neId) {
    message.warning({
      content: 'No Found NE Type',
      duration: 2,
    });
    return;
  }
  if (state.dataType === 'options' && state.data.mode === 'client' && state.data.host === '') {
    message.warning({
      content: 'Please fill in the Host',
      duration: 2,
    });
    return;
  }
  if (state.dataType === 'command' && state.data.command === '') {
    message.warning({
      content: 'Please fill in the Command',
      duration: 2,
    });
    return;
  }

  // 网元切换时重置
  if (neType !== state.params.neType || neId !== state.params.neId) {
    state.initialized = false;
    state.params.neType = neType;
    state.params.neId = neId;
  }

  // 软件版本检查
  state.params.neType = neType;
  state.params.neId = neId;
  const resVersion = await iperfV({
    neType,
    neId,
    version: state.data.version,
  });
  if (resVersion.code !== RESULT_CODE_SUCCESS) {
    Modal.confirm({
      title: t('common.tipTitle'),
      content: 'Not found if iperf is installed',
      onOk: () => fnInstall(),
    });
    return;
  } else {
    state.versionInfo = resVersion.data;
  }

  // 初始化的直接重发
  if (state.initialized) {
    fnResend();
    return;
  }
  state.initialized = true;
}

/**触发安装iperf */
function fnInstall() {
  const key = 'iperfI';
  message.loading({ content: t('common.loading'), key });
  const { neType, neId } = state.params;
  iperfI({ neType, neId, version: state.data.version }).then(res => {
    if (res.code === RESULT_CODE_SUCCESS) {
      message.success({
        content: 'install success',
        key,
        duration: 2,
      });
    } else {
      message.error({
        content: 'install fail',
        key,
        duration: 2,
      });
    }
  });
}

/**终端实例 */
const toolTerminal = ref();

/**重置并停止 */
function fnReset() {
  if (!toolTerminal.value) return;
  toolTerminal.value.ctrlC();
  // toolTerminal.value.clear();
  state.running = false;
}

/**重载发送 */
function fnResend() {
  if (!toolTerminal.value) return;
  state.running = true;
  toolTerminal.value.ctrlC();
  setTimeout(() => {
    toolTerminal.value.clear();
    const data = JSON.parse(JSON.stringify(state.data));
    if (state.dataType === 'options') data.command = '';
    toolTerminal.value.send('iperf', data);
  }, 1000);
}

/**终端初始连接*/
function fnConnect() {
  fnResend();
}

/**终端消息处理*/
function fnProcessMessage(data: string): string {
  // 查找的开始输出标记
  const parts: string[] = data.split('\u001b[?2004l\r');
  if (parts.length > 0) {
    if (parts[0].startsWith('^C') || parts[0].startsWith('\r')) {
      return '';
    }
    let text = parts[parts.length - 1];
    // 找到最后输出标记
    let lestIndex = text.lastIndexOf('\u001b[?2004h\u001b]0;');
    if (lestIndex !== -1) {
      text = text.substring(0, lestIndex);
    }
    if (text === '' || text === '\r\n' || text.startsWith('^C')) {
      return '';
    }
    // 是否还有最后输出标记
    lestIndex = text.lastIndexOf('\u001b[?2004h');
    if (lestIndex !== -1) {
      text = text.substring(0, lestIndex);
    }
    if (text.endsWith('# ')) {
      text = text.substring(0, text.lastIndexOf('\r\n') + 2);
    }

    // console.log({ parts, text });
    if (parts.length > 1 && parts[0].startsWith('iperf')) {
      return parts[0] + '\r\n' + text;
    }
    return text;
  }
  return data;
}

/**终端消息监听*/
function fnMessage(res: Record<string, any>) {
  const { code, requestId, data } = res;
  if (code === RESULT_CODE_ERROR) {
    console.warn(res.msg);
    return;
  }
  if (!requestId) return;
  let lestIndex = data.lastIndexOf('unable to');
  if (lestIndex !== -1) {
    state.running = false;
    return;
  }
  lestIndex = data.lastIndexOf('failed:');
  if (lestIndex !== -1) {
    state.running = false;
    return;
  }
  lestIndex = data.lastIndexOf('iperf Done.');
  if (lestIndex !== -1) {
    state.running = false;
    return;
  }
}

/**钩子函数，界面打开初始化*/
onMounted(() => {
  // 获取网元网元列表
  neInfoStore.fnNelist().then(res => {
    if (res.code === RESULT_CODE_SUCCESS) {
      if (res.data.length > 0) {
        // 过滤不可用的网元
        for (const item of neInfoStore.getNeCascaderOptions) {
          neCascaderOptions.value.push(item);
        }

        if (neCascaderOptions.value.length === 0) {
          message.warning({
            content: t('common.noData'),
            duration: 2,
          });
          return;
        }
      }
    } else {
      message.warning({
        content: t('common.noData'),
        duration: 2,
      });
    }
  });
});

/**钩子函数，界面关闭*/
onBeforeUnmount(() => {});
</script>

<template>
  <PageContainer>
    <a-card :bordered="false" :body-style="{ padding: '0px' }">
      <!-- 插槽-卡片左侧侧 -->
      <template #title>
        <a-space :size="8">
          <span>
            {{ t('views.ne.common.neType') }}:
            <a-cascader
              v-model:value="state.neType"
              :options="neCascaderOptions"
              :placeholder="t('common.selectPlease')"
              :disabled="state.running"
            />
          </span>
          <a-radio-group
            v-model:value="state.dataType"
            button-style="solid"
            :disabled="state.running"
          >
            <a-radio-button value="options">Options</a-radio-button>
            <a-radio-button value="command">Command</a-radio-button>
          </a-radio-group>
        </a-space>
      </template>

      <!-- 插槽-卡片右侧 -->
      <template #extra>
        <a-space :size="8">
          <a-button
            @click.prevent="fnIPerf()"
            type="primary"
            :loading="state.running"
          >
            <template #icon><PlayCircleOutlined /></template>
            {{ state.running ? 'Running' : 'Launch' }}
          </a-button>
          <a-button v-if="state.running" @click.prevent="fnReset()" danger>
            <template #icon><CloseCircleOutlined /></template>
            Stop
          </a-button>
          <!-- 版本信息 -->
          <a-popover
            trigger="click"
            placement="bottomRight"
            v-if="state.versionInfo.length > 0"
          >
            <template #content>
              <div v-for="v in state.versionInfo">{{ v }}</div>
            </template>
            <InfoCircleOutlined />
          </a-popover>
        </a-space>
      </template>

      <!-- options -->
      <a-form
        v-if="state.dataType === 'options'"
        :model="state.data"
        name="queryParams"
        layout="horizontal"
        :label-col="{ span: 6 }"
        :label-wrap="true"
        style="padding: 12px"
      >
        <a-row :gutter="16">
          <a-col :span="4" :offset="2">
            <a-form-item label="Mode" name="mode">
              <a-radio-group
                v-model:value="state.data.mode"
                :disabled="state.running"
                button-style="solid"
                size="small"
              >
                <a-radio-button value="client">Client</a-radio-button>
                <a-radio-button value="server">Server</a-radio-button>
              </a-radio-group>
            </a-form-item>
          </a-col>
          <a-col :span="4">
            <a-form-item
              label="Version"
              name="version"
              :label-col="{ span: 8 }"
              :label-wrap="true"
            >
              <a-radio-group
                v-model:value="state.data.version"
                :disabled="state.running"
                button-style="solid"
                size="small"
              >
                <a-radio-button value="V2">V2</a-radio-button>
                <a-radio-button value="V3">V3</a-radio-button>
              </a-radio-group>
            </a-form-item>
          </a-col>
          <a-col :lg="6" :md="6" :xs="12">
            <a-form-item label="Port" name="port">
              <a-input-number
                v-model:value="state.data.port"
                :disabled="state.running"
                allow-clear
                :placeholder="t('common.inputPlease')"
                style="width: 100%"
                :min="1024"
                :max="65535"
              ></a-input-number> </a-form-item
          ></a-col>
          <a-col :lg="6" :md="6" :xs="12">
            <a-form-item label="Interval" name="interval">
              <a-input-number
                v-model:value="state.data.interval"
                :disabled="state.running"
                allow-clear
                :placeholder="t('common.inputPlease')"
                style="width: 100%"
                :min="1"
                :max="30"
              ></a-input-number>
            </a-form-item>
          </a-col>
        </a-row>

        <template v-if="state.data.mode === 'client'">
          <a-form-item
            label="Host"
            name="host"
            help="run in client mode, connecting to <host>"
            :label-col="{ span: 3 }"
            :wrapper-col="{ span: 9 }"
            :label-wrap="true"
          >
            <a-input
              v-model:value="state.data.host"
              :disabled="state.running"
              allow-clear
              :placeholder="t('common.inputPlease')"
              style="width: 100%"
            >
            </a-input>
          </a-form-item>
          <a-row>
            <a-col :lg="12" :md="12" :xs="12">
              <a-form-item
                label="UDP"
                name="udp"
                help="use UDP rather than TCP"
              >
                <a-switch
                  v-model:checked="state.data.udp"
                  :disabled="state.running"
                />
              </a-form-item>
            </a-col>
            <a-col :lg="12" :md="12" :xs="12">
              <a-form-item
                label="Reverse"
                name="reverse"
                help="run in reverse mode (server sends, client receives)"
              >
                <a-switch
                  v-model:checked="state.data.reverse"
                  :disabled="state.running"
                />
              </a-form-item>
            </a-col>
            <a-col :lg="12" :md="12" :xs="12">
              <a-form-item
                label="Time"
                name="time"
                help="time in seconds to transmit for (default 10 secs)"
              >
                <a-input-number
                  v-model:value="state.data.time"
                  :disabled="state.running"
                  allow-clear
                  :placeholder="t('common.inputPlease')"
                  style="width: 100%"
                  :min="1"
                ></a-input-number>
              </a-form-item>
              <a-form-item
                label="Parallel"
                name="parallel"
                help="number of parallel client streams to run"
              >
                <a-input-number
                  v-model:value="state.data.parallel"
                  :disabled="state.running"
                  allow-clear
                  :placeholder="t('common.inputPlease')"
                  style="width: 100%"
                  :min="1"
                ></a-input-number>
              </a-form-item>
            </a-col>
            <a-col :lg="12" :md="12" :xs="12">
              <a-form-item
                label="Window"
                name="window"
                help="set window size / socket buffer size"
              >
                <a-input
                  v-model:value="state.data.window"
                  :disabled="state.running"
                  allow-clear
                  :placeholder="t('common.inputPlease')"
                  style="width: 100%"
                ></a-input>
              </a-form-item>
              <a-form-item
                label="Bitrate"
                name="bitrate"
                help="target bitrate in bits/sec (0 for unlimited)"
              >
                <a-input-number
                  v-model:value="state.data.bitrate"
                  :disabled="state.running"
                  allow-clear
                  :placeholder="t('common.inputPlease')"
                  style="width: 100%"
                  :min="1"
                ></a-input-number>
              </a-form-item>
            </a-col>
          </a-row>
        </template>
        <a-row v-else>
          <a-col :lg="12" :md="12" :xs="12">
            <a-form-item
              label="OneOff"
              name="oneOff"
              help=" handle one client connection then exit"
            >
              <a-switch
                v-model:checked="state.data.oneOff"
                :disabled="state.running"
              />
            </a-form-item>
          </a-col>
        </a-row>
      </a-form>

      <!-- command -->
      <div v-else style="padding: 12px">
        <a-input-group compact>
          <a-select
            v-model:value="state.data.version"
            :disabled="state.running"
          >
            <a-select-option value="V2">iperf</a-select-option>
            <a-select-option value="V3">iperf3</a-select-option>
          </a-select>
          <a-auto-complete
            v-model:value="state.data.command"
            :disabled="state.running"
            :options="[
              { value: '--help' },
              { value: '-c 172.5.16.100 -p 5201' },
              { value: '-s -p 5201' },
            ]"
            style="width: 400px"
            placeholder="client or server command"
          />
        </a-input-group>
      </div>

      <!-- 运行过程 -->
      <TerminalSSHView
        v-if="state.initialized"
        ref="toolTerminal"
        :id="`V${Date.now()}`"
        prefix="iperf"
        url="/tool/iperf/run"
        :ne-type="state.params.neType"
        :ne-id="state.params.neId"
        :rows="state.params.rows"
        :cols="state.params.cols"
        :process-messages="fnProcessMessage"
        style="height: 400px"
        @connect="fnConnect"
        @message="fnMessage"
      ></TerminalSSHView>
    </a-card>
  </PageContainer>
</template>

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