<script setup lang="ts">
import { reactive, onMounted, toRaw, watch } from 'vue';
import { ProModal } from 'antdv-pro-modal';
import { message, Form, Modal } from 'ant-design-vue/es';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { NE_TYPE_LIST } from '@/constants/ne-constants';
import { regExpIPv4, regExpIPv6 } from '@/utils/regular-utils';
import { getNeInfo, addNeInfo, updateNeInfo } from '@/api/ne/neInfo';
import { neHostAuthorizedRSA, testNeHost } from '@/api/ne/neHost';
import useDictStore from '@/store/modules/dict';
import useI18n from '@/hooks/useI18n';
const { getDict } = useDictStore();
const { t } = useI18n();
const emit = defineEmits(['ok', 'cancel', 'update:open']);
const props = defineProps({
  open: {
    type: Boolean,
    default: false,
  },
  editId: {
    type: Number,
    default: 0,
  },
});

/**字典数据 */
let dict: {
  /**主机类型 */
  neHostType: DictType[];
  /**分组 */
  neHostGroupId: DictType[];
  /**认证模式 */
  neHostAuthMode: DictType[];
} = reactive({
  neHostType: [],
  neHostGroupId: [],
  neHostAuthMode: [],
});

/**
 * 测试主机连接
 */
function fnHostTest(row: Record<string, any>) {
  if (modalState.confirmLoading || !row.addr || !row.port) return;
  modalState.confirmLoading = true;
  const hide = message.loading(t('common.loading'), 0);
  testNeHost(row)
    .then(res => {
      if (res.code === RESULT_CODE_SUCCESS) {
        message.success({
          content: `${row.addr}:${row.port} ${t('views.ne.neHost.testOk')}`,
          duration: 2,
        });
      } else {
        message.error({
          content: `${row.addr}:${row.port} ${res.msg}`,
          duration: 2,
        });
      }
    })
    .finally(() => {
      hide();
      modalState.confirmLoading = false;
    });
}

/**测试主机连接-免密直连 */
function fnHostAuthorized(row: Record<string, any>) {
  if (modalState.confirmLoading) return;

  Modal.confirm({
    title: t('common.tipTitle'),
    content: t('views.ne.neHost.authRSATip'),
    onOk: () => {
      modalState.confirmLoading = true;
      neHostAuthorizedRSA(row).then(res => {
        modalState.confirmLoading = false;
        if (res.code === RESULT_CODE_SUCCESS) {
          message.success(t('common.operateOk'), 3);
        } else {
          message.error(t('common.operateErr'), 3);
        }
      });
    },
  });
}

/**对话框对象信息状态类型 */
type ModalStateType = {
  /**新增框或修改框是否显示 */
  openByEdit: boolean;
  /**标题 */
  title: string;
  /**表单数据 */
  from: Record<string, any>;
  /**确定按钮 loading */
  confirmLoading: boolean;
};

/**对话框对象信息状态 */
let modalState: ModalStateType = reactive({
  openByEdit: false,
  title: '网元',
  from: {
    id: undefined,
    neId: '001',
    neType: 'AMF',
    neName: '',
    ip: '',
    port: 33030,
    pvFlag: 'PNF',
    rmUid: '4400HXAMF001',
    neAddress: '',
    dn: '',
    vendorName: '',
    province: 'Area',
    remark: '',
    // 主机
    hosts: [
      {
        id: undefined,
        hostType: 'ssh',
        groupId: '1',
        title: 'SSH_NE_22',
        addr: '',
        port: 22,
        user: 'omcuser',
        authMode: '2',
        password: '',
        privateKey: '',
        passPhrase: '',
        remark: '',
      },
      {
        id: undefined,
        hostType: 'telnet',
        groupId: '1',
        title: 'Telnet_NE_4100',
        addr: '',
        port: 4100,
        user: 'admin',
        authMode: '0',
        password: 'admin',
        remark: '',
      },
    ],
  },
  confirmLoading: false,
});

/**对话框内表单属性和校验规则 */
const modalStateFrom = Form.useForm(
  modalState.from,
  reactive({
    neType: [
      {
        required: true,
        message: t('views.ne.common.neTypePlease'),
      },
    ],
    neId: [
      {
        required: true,
        message: t('views.ne.common.neIdPlease'),
      },
    ],
    rmUid: [
      {
        required: true,
        message: t('views.ne.common.rmUidPlease'),
      },
    ],
    ip: [
      {
        required: true,
        validator: modalStateFromEqualIPV4AndIPV6,
      },
    ],
    neName: [
      {
        required: true,
        message: t('views.ne.common.neNamePlease'),
      },
    ],
  })
);

/**表单验证IP地址是否有效 */
function modalStateFromEqualIPV4AndIPV6(
  rule: Record<string, any>,
  value: string,
  callback: (error?: string) => void
) {
  if (!value) {
    return Promise.reject(t('views.ne.common.ipAddrPlease'));
  }

  if (value.indexOf('.') === -1 && value.indexOf(':') === -1) {
    return Promise.reject(t('valid.ipPlease'));
  }
  if (value.indexOf('.') !== -1 && !regExpIPv4.test(value)) {
    return Promise.reject(t('valid.ipv4Reg'));
  }
  if (value.indexOf(':') !== -1 && !regExpIPv6.test(value)) {
    return Promise.reject(t('valid.ipv6Reg'));
  }
  return Promise.resolve();
}

/**
 * 对话框弹出显示为 新增或者修改
 * @param editId 网元id, 不传为新增
 */
function fnModalVisibleByEdit(editId: number) {
  if (editId <= 0) {
    modalStateFrom.resetFields();
    modalState.title = t('views.ne.neInfo.addTitle');
    modalState.openByEdit = true;
  } else {
    if (modalState.confirmLoading) return;
    const hide = message.loading(t('common.loading'), 0);
    modalState.confirmLoading = true;
    getNeInfo(editId).then(res => {
      modalState.confirmLoading = false;
      hide();
      if (res.code === RESULT_CODE_SUCCESS) {
        Object.assign(modalState.from, res.data);
        modalState.title = t('views.ne.neInfo.editTitle');
        modalState.openByEdit = true;
      } else {
        message.error(t('common.getInfoFail'), 2);
      }
    });
  }
}

/**
 * 对话框弹出确认执行函数
 * 进行表达规则校验
 */
function fnModalOk() {
  modalStateFrom
    .validate()
    .then(e => {
      modalState.confirmLoading = true;
      const from = toRaw(modalState.from);
      const result = from.id ? updateNeInfo(from) : addNeInfo(from);
      const hide = message.loading(t('common.loading'), 0);
      result
        .then(res => {
          if (res.code === RESULT_CODE_SUCCESS) {
            message.success(t('common.operateOk'), 3);
            // 返回无引用信息
            emit('ok', JSON.parse(JSON.stringify(from)));
            fnModalCancel();
          } else {
            message.error({
              content: `${res.msg}`,
              duration: 3,
            });
          }
        })
        .finally(() => {
          hide();
          modalState.confirmLoading = false;
        });
    })
    .catch(e => {
      message.error(t('common.errorFields', { num: e.errorFields.length }), 3);
    });
}

/**
 * 对话框弹出关闭执行函数
 * 进行表达规则校验
 */
function fnModalCancel() {
  modalState.openByEdit = false;
  modalState.confirmLoading = false;
  modalStateFrom.resetFields();
  emit('cancel');
  emit('update:open', false);
}

/**表单修改网元类型 */
function fnNeTypeChange(v: any) {
  // 网元默认只含22和4100
  if (modalState.from.hosts.length === 3) {
    modalState.from.hosts.pop();
  }
  const hostsLen = modalState.from.hosts.length;
  // UPF标准版本可支持5002
  if (hostsLen === 2 && v === 'UPF') {
    modalState.from.hosts.push({
      id: undefined,
      hostType: 'telnet',
      groupId: '1',
      title: 'Telnet_NE_5002',
      addr: modalState.from.ip,
      port: 5002,
      user: 'admin',
      authMode: '0',
      password: 'admin',
      remark: '',
    });
  }
  // UDM可支持6379
  if (hostsLen === 2 && v === 'UDM') {
    modalState.from.hosts.push({
      id: undefined,
      hostType: 'redis',
      groupId: '1',
      title: 'REDIS_NE_6379',
      addr: modalState.from.ip,
      port: 6379,
      user: 'udmdb',
      authMode: '0',
      password: 'helloearth',
      dbName: '0',
      remark: '',
    });
  }

  modalState.from.rmUid = `4400HX${v}${modalState.from.neId}`; // 4400HX1AMF001
}

/**表单修改网元neId */
function fnNeIdChange(e: any) {
  const v = e.target.value;
  if (v.length < 1) return;
  modalState.from.rmUid = `4400HX${modalState.from.neType}${v}`; // 4400HX1AMF001
}

/**表单修改网元IP */
function fnNeIPChange(e: any) {
  const v = e.target.value;
  if (v.length < 7) return;
  for (const host of modalState.from.hosts) {
    host.addr = v;
  }
}

/**监听是否显示，初始数据 */
watch(
  () => props.open,
  val => {
    if (val) fnModalVisibleByEdit(props.editId);
  }
);

onMounted(() => {
  // 初始字典数据
  Promise.allSettled([
    getDict('ne_host_type'),
    getDict('ne_host_groupId'),
    getDict('ne_host_authMode'),
  ]).then(resArr => {
    if (resArr[0].status === 'fulfilled') {
      dict.neHostType = resArr[0].value;
    }
    if (resArr[1].status === 'fulfilled') {
      dict.neHostGroupId = resArr[1].value;
    }
    if (resArr[2].status === 'fulfilled') {
      dict.neHostAuthMode = resArr[2].value;
    }
  });
});
</script>

<template>
  <ProModal
    :drag="true"
    :width="800"
    :destroyOnClose="true"
    :body-style="{ maxHeight: '600px', 'overflow-y': 'auto' }"
    :keyboard="false"
    :mask-closable="false"
    :open="modalState.openByEdit"
    :title="modalState.title"
    :confirm-loading="modalState.confirmLoading"
    @ok="fnModalOk"
    @cancel="fnModalCancel"
  >
    <a-form
      name="modalStateFrom"
      layout="horizontal"
      :label-col="{ span: 6 }"
      :labelWrap="true"
    >
      <a-row>
        <a-col :lg="12" :md="12" :xs="24">
          <a-form-item
            :label="t('views.ne.common.neType')"
            name="neType"
            v-bind="modalStateFrom.validateInfos.neType"
          >
            <a-auto-complete
              v-model:value="modalState.from.neType"
              :options="NE_TYPE_LIST.map(v => ({ value: v }))"
              @change="fnNeTypeChange"
            >
              <a-input
                allow-clear
                :placeholder="t('common.inputPlease')"
                :maxlength="32"
              >
                <template #prefix>
                  <a-tooltip placement="topLeft">
                    <template #title>
                      {{ t('views.ne.common.neTypeTip') }}
                    </template>
                    <InfoCircleOutlined style="opacity: 0.45; color: inherit" />
                  </a-tooltip>
                </template>
              </a-input>
            </a-auto-complete>
          </a-form-item>
        </a-col>
        <a-col :lg="12" :md="12" :xs="24">
          <a-form-item
            :label="t('views.ne.neInfo.pvflag')"
            name="pvFlag"
            v-bind="modalStateFrom.validateInfos.pvFlag"
          >
            <a-select
              v-model:value="modalState.from.pvFlag"
              default-value="PNF"
            >
              <a-select-opt-group :label="t('views.ne.neInfo.pnf')">
                <a-select-option value="PNF">PNF</a-select-option>
              </a-select-opt-group>
              <a-select-opt-group :label="t('views.ne.neInfo.vnf')">
                <a-select-option value="VNF">VNF</a-select-option>
              </a-select-opt-group>
            </a-select>
          </a-form-item>
        </a-col>
      </a-row>

      <a-row>
        <a-col :lg="12" :md="12" :xs="24">
          <a-form-item
            :label="t('views.ne.common.neId')"
            name="neId"
            v-bind="modalStateFrom.validateInfos.neId"
          >
            <a-input
              v-model:value="modalState.from.neId"
              allow-clear
              :placeholder="t('common.inputPlease')"
              :maxlength="32"
              @change="fnNeIdChange"
            >
              <template #prefix>
                <a-tooltip placement="topLeft">
                  <template #title>
                    {{ t('views.ne.common.neIdTip') }}
                  </template>
                  <InfoCircleOutlined style="opacity: 0.45; color: inherit" />
                </a-tooltip>
              </template>
            </a-input>
          </a-form-item>
        </a-col>
        <a-col :lg="12" :md="12" :xs="24">
          <a-form-item
            :label="t('views.ne.common.neName')"
            name="neName"
            v-bind="modalStateFrom.validateInfos.neName"
          >
            <a-input
              v-model:value="modalState.from.neName"
              allow-clear
              :placeholder="t('common.inputPlease')"
              :maxlength="64"
            >
            </a-input>
          </a-form-item>
        </a-col>
      </a-row>

      <a-row>
        <a-col :lg="12" :md="12" :xs="24">
          <a-form-item
            :label="t('views.ne.common.ipAddr')"
            name="ip"
            v-bind="modalStateFrom.validateInfos.ip"
          >
            <a-input
              v-model:value="modalState.from.ip"
              allow-clear
              :placeholder="t('common.inputPlease')"
              :maxlength="128"
              @change="fnNeIPChange"
            >
              <template #prefix>
                <a-tooltip placement="topLeft">
                  <template #title>
                    <div>
                      {{ t('views.ne.common.ipAddrTip') }}
                    </div>
                  </template>
                  <InfoCircleOutlined style="opacity: 0.45; color: inherit" />
                </a-tooltip>
              </template>
            </a-input>
          </a-form-item>
        </a-col>
        <a-col :lg="12" :md="12" :xs="24">
          <a-form-item
            :label="t('views.ne.common.port')"
            name="port"
            v-bind="modalStateFrom.validateInfos.port"
          >
            <a-input-number
              v-model:value="modalState.from.port"
              style="width: 100%"
              :min="1"
              :max="65535"
              :maxlength="5"
              placeholder="<=65535"
            >
              <template #prefix>
                <a-tooltip placement="topLeft">
                  <template #title>
                    <div>{{ t('views.ne.common.portTip') }}</div>
                  </template>
                  <InfoCircleOutlined style="opacity: 0.45; color: inherit" />
                </a-tooltip>
              </template>
            </a-input-number>
          </a-form-item>
        </a-col>
      </a-row>

      <a-form-item
        :label="t('views.ne.common.rmUid')"
        name="rmUid"
        v-bind="modalStateFrom.validateInfos.rmUid"
        :label-col="{ span: 3 }"
        :labelWrap="true"
      >
        <a-input
          v-model:value="modalState.from.rmUid"
          allow-clear
          :placeholder="t('common.inputPlease')"
          :maxlength="40"
        >
          <template #prefix>
            <a-tooltip placement="topLeft">
              <template #title>
                <div>
                  {{ t('views.ne.common.rmUidTip') }}
                </div>
              </template>
              <InfoCircleOutlined style="opacity: 0.45; color: inherit" />
            </a-tooltip>
          </template>
        </a-input>
      </a-form-item>

      <a-row>
        <a-col :lg="12" :md="12" :xs="24">
          <a-form-item :label="t('views.ne.neInfo.neAddress')" name="neAddress">
            <a-input
              v-model:value="modalState.from.neAddress"
              allow-clear
              :placeholder="t('common.inputPlease')"
              :maxlength="64"
            >
              <template #prefix>
                <a-tooltip placement="topLeft">
                  <template #title>
                    <div>{{ t('views.ne.neInfo.neAddressTip') }}</div>
                  </template>
                  <InfoCircleOutlined style="opacity: 0.45; color: inherit" />
                </a-tooltip>
              </template>
            </a-input>
          </a-form-item>
        </a-col>
        <a-col :lg="12" :md="12" :xs="24">
          <a-form-item :label="t('views.ne.neInfo.dn')" name="dn">
            <a-input
              v-model:value="modalState.from.dn"
              allow-clear
              :placeholder="t('common.inputPlease')"
              :maxlength="255"
            ></a-input>
          </a-form-item>
        </a-col>
      </a-row>

      <a-row>
        <a-col :lg="12" :md="12" :xs="24">
          <a-form-item
            :label="t('views.ne.neInfo.vendorName')"
            name="vendorName"
          >
            <a-input
              v-model:value="modalState.from.vendorName"
              allow-clear
              :placeholder="t('common.inputPlease')"
              :maxlength="64"
            >
            </a-input>
          </a-form-item>
        </a-col>
        <a-col :lg="12" :md="12" :xs="24">
          <a-form-item :label="t('views.ne.neInfo.province')" name="province">
            <a-input
              v-model:value="modalState.from.province"
              allow-clear
              :placeholder="t('common.inputPlease')"
              :maxlength="32"
            ></a-input>
          </a-form-item>
        </a-col>
      </a-row>

      <a-form-item
        :label="t('common.remark')"
        :label-col="{ span: 3 }"
        :label-wrap="true"
      >
        <a-textarea
          v-model:value="modalState.from.remark"
          :auto-size="{ minRows: 1, maxRows: 6 }"
          :maxlength="450"
          :show-count="true"
          :placeholder="t('common.inputPlease')"
        />
      </a-form-item>

      <!-- 主机连接配置 -->
      <a-divider orientation="left">
        {{ t('views.ne.neInfo.hostConfig') }}
      </a-divider>
      <a-collapse class="collapse" ghost>
        <a-collapse-panel
          v-for="host in modalState.from.hosts.filter(
            (s:any) => !(s.hostType === 'telnet' &&  modalState.from.neType === 'OMC')
          )"
          :key="host.title"
        >
          <template #header>
            <span v-if="host.hostType === 'redis'"> DB {{ host.port }} </span>
            <span v-else>
              {{ `${host.hostType.toUpperCase()} ${host.port}` }}
            </span>
          </template>
          <a-row>
            <a-col :lg="12" :md="12" :xs="24">
              <a-form-item :label="t('views.ne.neHost.addr')">
                <a-input
                  v-model:value="host.addr"
                  allow-clear
                  :maxlength="128"
                  :placeholder="t('common.inputPlease')"
                >
                </a-input>
              </a-form-item>
            </a-col>
            <a-col :lg="12" :md="12" :xs="24">
              <a-form-item
                :label="t('views.ne.neHost.port')"
                name="neHost.port"
              >
                <a-input-number
                  v-model:value="host.port"
                  :min="10"
                  :max="65535"
                  :step="1"
                  :maxlength="5"
                  style="width: 100%"
                ></a-input-number>
              </a-form-item>
            </a-col>
          </a-row>

          <a-form-item
            v-if="host.hostType === 'telnet'"
            :label="t('views.ne.neHost.user')"
            :label-col="{ span: 3 }"
            :label-wrap="true"
          >
            <a-input
              v-model:value="host.user"
              allow-clear
              :maxlength="32"
              :placeholder="t('common.inputPlease')"
            >
            </a-input>
          </a-form-item>

          <a-row v-if="host.hostType === 'ssh'">
            <a-col :lg="12" :md="12" :xs="24">
              <a-form-item :label="t('views.ne.neHost.user')">
                <a-input
                  v-model:value="host.user"
                  allow-clear
                  :maxlength="32"
                  :placeholder="t('common.inputPlease')"
                >
                </a-input>
              </a-form-item>
            </a-col>
            <a-col :lg="12" :md="12" :xs="24">
              <a-form-item :label="t('views.ne.neHost.authMode')">
                <a-select
                  v-model:value="host.authMode"
                  default-value="0"
                  :options="dict.neHostAuthMode"
                >
                </a-select>
              </a-form-item>
            </a-col>
          </a-row>

          <a-form-item
            v-if="host.authMode === '0'"
            :label="t('views.ne.neHost.password')"
            :label-col="{ span: 3 }"
            :label-wrap="true"
          >
            <a-input-password
              v-model:value="host.password"
              :maxlength="128"
              :placeholder="t('common.inputPlease')"
            >
            </a-input-password>
          </a-form-item>
          <template v-if="host.authMode === '1'">
            <a-form-item
              :label="t('views.ne.neHost.privateKey')"
              :label-col="{ span: 3 }"
              :label-wrap="true"
            >
              <a-textarea
                v-model:value="host.privateKey"
                :auto-size="{ minRows: 4, maxRows: 6 }"
                :maxlength="3000"
                :show-count="true"
                :placeholder="t('views.ne.neHost.privateKeyPlease')"
              />
            </a-form-item>

            <a-form-item
              :label="t('views.ne.neHost.passPhrase')"
              :label-col="{ span: 3 }"
              :label-wrap="true"
            >
              <a-input-password
                v-model:value="host.passPhrase"
                :maxlength="128"
                :placeholder="t('common.inputPlease')"
              >
              </a-input-password>
            </a-form-item>
          </template>

          <a-form-item
            v-if="host.hostType === 'mysql'"
            :label="t('views.ne.neHost.database')"
            :label-col="{ span: 3 }"
            :label-wrap="true"
          >
            <a-input
              v-model:value="host.dbName"
              allow-clear
              :maxlength="32"
              :placeholder="t('common.inputPlease')"
            >
            </a-input>
          </a-form-item>

          <a-form-item
            :label="t('common.remark')"
            :label-col="{ span: 3 }"
            :label-wrap="true"
          >
            <a-textarea
              v-model:value="host.remark"
              :auto-size="{ minRows: 1, maxRows: 6 }"
              :maxlength="450"
              :show-count="true"
              :placeholder="t('common.inputPlease')"
            />
          </a-form-item>

          <!-- 测试 -->
          <a-form-item
            :label="t('views.ne.neHost.test')"
            name="test"
            :label-col="{ span: 3 }"
            :label-wrap="true"
          >
            <a-button
              type="primary"
              shape="round"
              @click="fnHostTest(host)"
              :loading="modalState.confirmLoading"
            >
              <template #icon><LinkOutlined /></template>
            </a-button>

            <a-button
              type="link"
              @click="fnHostAuthorized(host)"
              :loading="modalState.confirmLoading"
              v-if="host.hostType === 'ssh' && host.authMode !== '2'"
            >
              {{ t('views.ne.neHost.authRSA') }}
            </a-button>
          </a-form-item>
        </a-collapse-panel>
      </a-collapse>
    </a-form>
  </ProModal>
</template>

<style lang="less" scoped>
.collapse :deep(.ant-collapse-item) > .ant-collapse-header {
  padding-left: 0;
  padding-right: 0;
}
.collapse-header {
  flex: 1;
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}
</style>
