<script setup lang="ts">
import { reactive, ref, onMounted, toRaw } from 'vue';
import { PageContainer } from '@ant-design-vue/pro-layout';
import { message } from 'ant-design-vue/lib';
import CodemirrorEdite from '@/components/CodemirrorEdite/index.vue';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import useNeInfoStore from '@/store/modules/neinfo';
import { regExpIPv4, regExpIPv6 } from '@/utils/regular-utils';
import useI18n from '@/hooks/useI18n';
import { getMMLByOMC, sendMMlByOMC } from '@/api/mmlManage/omcOperate';
const { t } = useI18n();

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

/**对象信息状态类型 */
type StateType = {
  /**网元ID */
  neId: string;
  /**命令数据 loading */
  mmlLoading: boolean;
  /**命令数据 tree */
  mmlTreeData: any[];
  /**命令选中 */
  mmlSelect: Record<string, any>;
  /**表单数据 */
  from: Record<string, any>;
  /**命令发送日志 */
  mmlCmdLog: string;
};

/**对象信息状态 */
let state: StateType = reactive({
  neId: '',
  mmlLoading: true,
  mmlTreeData: [],
  mmlSelect: {},
  from: {
    sendLoading: false,
  },
  mmlCmdLog: '',
});

/**查询可选命令列表 */
function fnTreeSelect(_: any, info: any) {
  state.mmlSelect = info.node.dataRef;
  state.from = {};
  // state.mmlCmdLog = '';
}

/**清空控制台日志 */
function fnCleanCmdLog() {
  state.mmlCmdLog = '';
}

/**清空表单 */
function fnCleanFrom() {
  state.from = {};
}

/**命令发送 */
function fnSendMML() {
  if (state.from.sendLoading) {
    return;
  }
  const operation = state.mmlSelect.operation;
  const object = state.mmlSelect.object;
  let cmdStr = '';
  // 根据参数取值
  let argsArr: string[] = [];
  const param = toRaw(state.mmlSelect.param) || [];
  const from = toRaw(state.from);
  for (const item of param) {
    const value = from[item.name];

    // 是否必填项且有效值
    const notV = value === null || value === undefined || value === '';
    if (item.optional === 'false' && notV) {
      message.warning(`必填参数：${item.display}`, 2);
      return;
    }

    // 检查是否存在值
    if (!Reflect.has(from, item.name) || notV) {
      continue;
    }

    // 检查规则
    const [ok, msg] = ruleVerification(item, from[item.name]);
    if (!ok) {
      message.warning({
        content: `${msg}`,
        duration: 3,
      });
      return;
    }

    argsArr.push(`${item.name}=${from[item.name]}`);
  }

  // 拼装命令
  const argsStr = argsArr.join(',');
  if (object && argsStr) {
    cmdStr = `${operation} ${object}:${argsStr}`;
  } else if (object) {
    cmdStr = `${operation} ${object}`;
  } else {
    cmdStr = `${operation} ${argsStr}`;
  }
  cmdStr = cmdStr.trim();

  // 发送
  state.mmlCmdLog += `${cmdStr}\n`;
  state.from.sendLoading = true;
  sendMMlByOMC(state.neId, cmdStr).then(res => {
    state.from.sendLoading = false;
    if (res.code === RESULT_CODE_SUCCESS) {
      let resultStr = res.data;
      resultStr = resultStr.replace(/(\r\n|\n)/g, '\n');
      state.mmlCmdLog += `${resultStr}\n`;
    } else {
      state.mmlCmdLog += `${res.msg}\n`;
    }
  });
}

/**规则校验 */
function ruleVerification(
  row: Record<string, any>,
  value: any
): (string | boolean)[] {
  let result = [true, ''];
  const type = row.type;
  const filter = row.filter;
  const display = row.display;

  switch (type) {
    case 'int':
      if (filter && filter.indexOf('~') !== -1) {
        const filterArr = filter.split('~');
        const minInt = parseInt(filterArr[0]);
        const maxInt = parseInt(filterArr[1]);
        const valueInt = parseInt(value);
        if (valueInt < minInt || valueInt > maxInt) {
          return [false, `${display} 参数值不在合理范围 ${filter}`];
        }
      }
      break;
    case 'ipv4':
      if (!regExpIPv4.test(value)) {
        return [false, `${display} 不是合法的IPV4地址`];
      }
      break;
    case 'ipv6':
      if (!regExpIPv6.test(value)) {
        return [false, `${display} 不是合法的IPV6地址`];
      }
      break;
    case 'enum':
      if (filter && filter.indexOf('{') === 1) {
        let filterJson: Record<string, any> = {};
        try {
          filterJson = JSON.parse(filter); //string---json
        } catch (error) {
          console.error(error);
        }

        if (!Object.keys(filterJson).includes(`${value}`)) {
          return [false, `${display} 不是合理的枚举值`];
        }
      }
      break;
    case 'bool':
      if (filter && filter.indexOf('{') === 1) {
        let filterJson: Record<string, any> = {};
        try {
          filterJson = JSON.parse(filter); //string---json
        } catch (error) {
          console.error(error);
        }

        if (!Object.values(filterJson).includes(`${value}`)) {
          return [false, `${display} 不是合理的布尔类型的值`];
        }
      }
      break;
    case 'string':
      if (filter && filter.indexOf('~') !== -1) {
        try {
          const filterArr = filter.split('~');
          let rule = new RegExp(
            '^\\S{' + filterArr[0] + ',' + filterArr[1] + '}$'
          );
          if (!rule.test(value)) {
            return [false, `${display} 参数值不合理`];
          }
        } catch (error) {
          console.error(error);
        }
      }

      break;
    case 'regex':
      if (filter) {
        try {
          let regex = new RegExp(filter);
          if (!regex.test(value)) {
            return [false, `${display} 参数值不合理`];
          }
        } catch (error) {
          console.error(error);
        }
      }
      break;

    default:
      return [false, `${display} 输入值是未知类型`];
  }
  return result;
}

/**查询可选命令列表 */
function fnGetList() {
  getMMLByOMC().then(res => {
    if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
      // 构建树结构
      const treeArr: Record<string, any>[] = [];
      for (const item of res.data) {
        const id = item['id'];
        const object = item['object'];
        const operation = item['operation'];
        const mmlDisplay = item['mmlDisplay'];
        // 可选属性参数
        let param = [];
        try {
          param = JSON.parse(item['paramJson']);
        } catch (error) {
          console.error(error);
        }

        // 遍历检查大类
        const treeItem = treeArr.find(i => i.key == item['category']);
        if (!treeItem) {
          treeArr.push({
            title: item['catDisplay'],
            key: item['category'],
            selectable: false,
            children: [
              { key: id, title: mmlDisplay, object, operation, param },
            ],
          });
        } else {
          treeItem.children.push({
            key: id,
            title: mmlDisplay,
            object,
            operation,
            param,
          });
        }
      }
      state.mmlTreeData = treeArr;
    }
    state.mmlLoading = false;
  });
}

onMounted(() => {
  // 获取网元网元列表
  useNeInfoStore()
    .fnNelist()
    .then(res => {
      if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
        if (res.data.length > 0) {
          let arr: Record<string, any>[] = [];
          res.data.forEach(i => {
            if (i.neType === 'OMC') {
              arr.push({ value: i.neId, label: i.neName });
            }
          });
          neOtions.value = arr;
          if (arr.length > 0) {
            state.neId = arr[0].value;
            // 获取列表数据
            fnGetList();
          }
        } else {
          message.warning({
            content: `暂无OMC网元`,
            duration: 5,
          });
        }
      } else {
        message.warning({
          content: `暂无网元列表数据`,
          duration: 2,
        });
      }
    });
});
</script>

<template>
  <PageContainer>
    <a-row :gutter="16">
      <a-col :span="6">
        <!-- 命令导航 -->
        <a-card
          size="small"
          :bordered="false"
          title="命令导航"
          :loading="state.mmlLoading"
        >
          <a-form layout="vertical" autocomplete="off">
            <a-form-item name="neId ">
              <a-select
                v-model:value="state.neId"
                :options="neOtions"
                placeholder="请选择OMC操作命令"
              />
            </a-form-item>
            <a-form-item name="listeningPort">
              <a-directory-tree
                :tree-data="state.mmlTreeData"
                @select="fnTreeSelect"
              ></a-directory-tree>
            </a-form-item>
          </a-form>
        </a-card>
      </a-col>
      <a-col :span="18">
        <!-- 命令参数输入 -->
        <a-card
          size="small"
          :bordered="false"
          :loading="!state.mmlSelect.title"
        >
          <template #title>
            <a-typography-text strong v-if="state.mmlSelect.title">
              {{ state.mmlSelect.title }}
            </a-typography-text>
            <a-typography-text type="danger" v-else>
              左侧命令导航中选择要操作项！
            </a-typography-text>
          </template>
          <!-- 插槽-卡片右侧 -->
          <template #extra>
            <a-space :size="8">
              <a-button
                type="default"
                size="small"
                @click.prevent="fnCleanFrom"
                v-if="!!state.mmlSelect.param"
              >
                <template #icon>
                  <ClearOutlined />
                </template>
                清除表单
              </a-button>
              <a-button
                type="primary"
                size="small"
                :disabled="!state.mmlSelect.title"
                :loading="state.from.sendLoading"
                @click.prevent="fnSendMML"
              >
                <template #icon>
                  <SendOutlined />
                </template>
                执行
              </a-button>
            </a-space>
          </template>

          <a-form
            layout="vertical"
            autocomplete="off"
            :validate-on-rule-change="false"
            :validateTrigger="[]"
          >
            <a-row :gutter="16">
              <a-col
                :lg="6"
                :md="12"
                :xs="24"
                v-for="item in state.mmlSelect.param"
              >
                <a-form-item
                  :label="item.display"
                  :name="item.name"
                  :required="item.optional === 'false'"
                >
                  <a-tooltip>
                    <template #title v-if="item.comment">
                      {{ item.comment }}
                    </template>
                    <a-input
                      v-if="
                        ['string', 'ipv6', 'ipv4', 'regex'].includes(item.type)
                      "
                      v-model:value="state.from[item.name]"
                      :placeholder="item.filter"
                    ></a-input>
                    <a-input-number
                      v-else-if="item.type === 'int'"
                      v-model:value="state.from[item.name]"
                      :min="0"
                      :max="65535"
                      :placeholder="item.filter"
                      style="width: 100%"
                    ></a-input-number>
                    <a-switch
                      v-else-if="item.type === 'bool'"
                      v-model:checked="state.from[item.name]"
                      :checked-children="t('common.switch.open')"
                      :un-checked-children="t('common.switch.shut')"
                    ></a-switch>
                    <a-select
                      v-else-if="item.type === 'enum'"
                      v-model:value="state.from[item.name]"
                      :placeholder="item.filter"
                      :allow-clear="true"
                    >
                      <a-select-option
                        :value="v"
                        :key="v"
                        v-for="(k, v) in JSON.parse(item.filter)"
                      >
                        {{ k }}
                      </a-select-option>
                    </a-select>
                  </a-tooltip>
                </a-form-item>
              </a-col>
            </a-row>
          </a-form>
        </a-card>

        <!-- 命令展示 -->
        <a-card
          title="控制台"
          :bordered="false"
          size="small"
          :body-style="{ padding: 0 }"
          style="margin-top: 16px"
          v-show="state.mmlSelect.title"
        >
          <!-- 插槽-卡片右侧 -->
          <template #extra>
            <a-space :size="8" align="center">
              <a-button
                type="default"
                size="small"
                @click.prevent="fnCleanCmdLog"
              >
                <template #icon>
                  <ClearOutlined />
                </template>
                清除日志
              </a-button>
            </a-space>
          </template>

          <CodemirrorEdite
            v-model:value="state.mmlCmdLog"
            :disabled="true"
            :editor-style="{ height: '500px !important' }"
            placeholder="等待发送命令"
          ></CodemirrorEdite>
        </a-card>
      </a-col>
    </a-row>
  </PageContainer>
</template>

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