<script lang="ts" setup>
import { onMounted, Ref, ref, reactive, computed } from 'vue';
import { getPortInfo, setPortInfo } from '@/services/port-service';
import { IPortListItem } from '@/model/service-interface';
import { traduction } from '@/utils/language';
import { ElMessage as elMessage } from 'element-plus';
import { IconAlarm } from '@computing/opendesign-icons';
import { getStoreData, loading, setStoreData } from '@/utils/composition';
import { BaseValidators } from '@/validators/base-validators';
import Dialog from '@/components/Dialog/Dialog.vue';
import Lock from '@/components/Lock/Lock.vue';
import ErrorIcon from '@/components/ErrorIcon/ErrorIcon.vue';
import ClearableIcon from '@/components/ClearableIcon/ClearableIcon.vue';
import Schema from 'async-validator';
import TableNoData from '@/components/TableNoData/TableNoData.vue';
import useStore from '@/stores';

const checkSupported = reactive({
  KVM: getStoreData('loct', 'kvmspt'),
  Video: getStoreData('loct', 'kvmspt'),
  VMM: getStoreData('loct', 'vmmspt'),
  VNC: getStoreData('loct', 'vncspt'),
  SNMPAgent: getStoreData('loct', 'snmpspt'),
});

const isLocked = computed(() => {
  return getStoreData('glob', 'systemLocked');
});
const dialogRef = ref();
const isEdit = ref(false);
const disabled = ref(true);
const dialogConfig = reactive({
  title: traduction('COMMON_INFORMATION'),
  content: traduction('SERVICE_TIMESSAGE_CONTENT'),
  okButton: { label: traduction('COMMON_CONFIRM') },
});
const RMCPdialogRef = ref();
const RMCPdiaginfo = reactive({
  id: '',
  content: '',
  title: '',
  okButton: {
    id: 'secondConfirm_ok_btn',
    label: traduction('SERVICE_PORT_RMCP_CONFIRM'),
    hide: false,
  },
});
let dialogId: string;
// 记录表格数据变化对应的行
const changeData = {
  port1: {},
  port2: {},
  switch: {},
};

// 端口校验规则 1.必填 2.数字 3.整型 4.范围1-65535
const rules: any = {
  port1Edit: [
    BaseValidators.Required({ trigger: 'change', message: traduction('VALIDTOR_RANGE') }),
    BaseValidators.Integer({ trigger: 'change', message: traduction('VALIDTOR_RANGE') }),
    BaseValidators.Range({ range: [1, 65535], trigger: 'change' }),
  ],
  port2Edit: [
    BaseValidators.Required({ trigger: 'change', message: traduction('VALIDTOR_RANGE') }),
    BaseValidators.Integer({ trigger: 'change', message: traduction('VALIDTOR_RANGE') }),
    BaseValidators.Range({ range: [1, 65535], trigger: 'change' }),
  ],
};
const formSchema = new Schema(rules);
const tableData: Ref<IPortListItem[]> = ref([]);

// 分页数据
const currentPage = ref(1);
const pageSize = ref(15);
const total = ref(tableData.value.length);
// 分页事件
function handleSizeChange() {}

// 点击编辑按钮事件
function editPort(showEdit: boolean) {
  disabled.value = true;
  clearChangeData();
  tableData.value?.forEach(item => {
    item.port1Edit = item.port1;
    item.port2Edit = item.port2;
    item.enabledEdit = item.enabled;
  });
  isEdit.value = showEdit;
}

// 恢复默认端口
function port1Rest(row: IPortListItem) {
  row.port1Edit = row.port1Default;
  recordChange(row, 1, row.name, row.port1Edit);
  computeSaveState();
}
function port2Rest(row: IPortListItem) {
  row.port2Edit = row.port2Default;
  recordChange(row, 2, row.name, row.port1Edit);
  computeSaveState();
}

// 切换switch状态事件
function switchChange(row: IPortListItem) {
  if ((row.name === 'IPMILANRMCP' || row.name === 'IPMILANRMCPPlus') && row.enabledEdit === true) {
    RMCPdiaginfo.id = 'RMCPDialog';
    RMCPdiaginfo.title = traduction('COMMON_CONFIRM');
    RMCPdiaginfo.content = traduction('SERVICE_PORT_RMCP_CONFIRM_TIP');
    dialogId = row.name;
    RMCPdialogRef.value.show();
  } else {
    if (row.enabled !== row.enabledEdit) {
      changeData.switch[row.name] = row.enabledEdit;
    } else {
      delete changeData.switch[row.name];
    }
  }
  computeSaveState();
}

// switch切换前钩子函数
function beforeStateChange(row: IPortListItem) {
  return function () {
    // 双因素登录，无法操作SSH端口
    if (row.name === 'SSH' && getStoreData('loct', 'twofac')) {
      setStoreData('event', 'alertMessage', {
        type: 'error',
        message: traduction('IBMC_SSH_OPEN_FORRBIDEN_TIP'),
      });
      return false;
    }

    // 非双因素下关闭SSH端口
    if (row.name === 'SSH' && row.enabledEdit && row.enabled) {
      showWarningInfo(traduction('IBMC_SSH_CLOSE_TIP', { softwareName: useStore().state.loct.sn }));
    }

    if (row.name === 'HTTP' && row.enabledEdit && row.enabled) {
      showWarningInfo(traduction('IBMC_HTTP_CLOSE_TIP', { softwareName: useStore().state.loct.sn }));
    }

    if (row.name === 'HTTPS' && row.enabledEdit && row.enabled) {
      showWarningInfo(traduction('IBMC_HTTPS_CLOSE_TIP', { softwareName: useStore().state.loct.sn }));
    }

    // IPMI，VNC由关闭状态变为开启状态时，应提示警告信息
    if (!row.enabledEdit && row.name === 'VNC') {
      showWarningInfo(traduction('SERVICE_OPEN_VNC'));
    }

    return true;
  };
}

// 自定义输入框组件输入时，同时修改当前组件的绑定值
function resetControlValue(row: IPortListItem, portNum: number, key: string, value: string) {
  recordChange(row, portNum, key, value);
  computeSaveState();
}

function recordChange(row: IPortListItem, portNum: number, key: string, value: string) {
  row[key] = value;
  const portTarget = portNum === 1 ? 'port1' : 'port2';
  const portEditTarget = portNum === 1 ? 'port1Edit' : 'port2Edit';
  const portValue = String(row[portTarget]);
  const portEditValue = String(row[portEditTarget]);
  if (portValue !== portEditValue) {
    changeData[portTarget][row.name] = row[portEditTarget];
  } else {
    delete changeData[portTarget][row.name];
  }
}

// 创建校验对象
function createValidatorData() {
  const dataArr: any = [];
  tableData.value.map(item => {
    const temp: any = {};
    if (item.name === 'IPMILANRMCPPlus') {
      return;
    } else if (item.name === 'IPMILANRMCP') {
      temp.port1Edit = item.port1Edit;
      temp.port2Edit = item.port2Edit;
    } else {
      temp.port1Edit = item.port1Edit;
    }

    if (Object.keys(temp).length > 0) {
      dataArr.push(temp);
    }
  });

  return dataArr;
}

// 实时校验表单数据
function realingValidataor() {
  const data = createValidatorData();
  let state = true;
  data.forEach((item: any) => {
    formSchema.validate(item, (errors: any) => {
      const _state = errors ? false : true;
      state = state && _state;
    });
  });
  return state;
}

/**
 * 保存按钮的状态
 * 1. 表单是否通过校验
 * 2. 表单内容是否发生了变化
 * 3. 表单disabled的条件，1、未通过校验，2、数据无变化
 */
function computeSaveState() {
  // 1. 表单是否通过了校验
  let noError = realingValidataor();
  // 2. 数据是否发生了变化
  const isChanged =
    Object.keys(changeData.port1).length > 0 ||
    Object.keys(changeData.port2).length > 0 ||
    Object.keys(changeData.switch).length > 0;
  if (noError && isChanged) {
    disabled.value = false;
  } else {
    disabled.value = true;
  }
}

function cteateChangeParam() {
  const temp: { [key: string]: any } = {};
  tableData.value.forEach(item => {
    const tempItem: { [key: string]: any } = {};
    if (item.enabled !== item.enabledEdit) {
      tempItem.Enabled = item.enabledEdit;
    }

    if (item.port1 !== item.port1Edit) {
      tempItem.Port = parseInt(item.port1Edit, 10);
    }

    if (item.port2 !== item.port2Edit) {
      tempItem.SparePort = parseInt(item.port2Edit, 10);
    }

    if (Object.keys(tempItem).length > 0) {
      temp[item.name] = tempItem;
    }
  });

  if (temp.KVM) {
    temp.KVM1 = temp.KVM;
    delete temp.KVM;
  }

  if (temp.VMM) {
    temp.VMM1 = temp.VMM;
    delete temp.VMM;
  }

  const keys = Object.keys(temp);
  const kvms = keys.filter(key => key.startsWith('KVM'));
  if (kvms.length > 0) {
    temp.KVM = [];
    kvms.forEach(key => {
      temp.KVM.push({ SystemId: parseInt(key.match(/\d+$/)?.[0] ?? '1', 10), ...temp[key] });
    });
    kvms.filter(key => key !== 'KVM').forEach(key => delete temp[key]);
  }

  const vmms = keys.filter(key => key.startsWith('VMM'));
  if (vmms.length > 0) {
    temp.VMM = [];
    vmms.forEach(key => {
      temp.VMM.push({ SystemId: parseInt(key.match(/\d+$/)?.[0] ?? '1', 10), ...temp[key] });
    });
    vmms.filter(key => key !== 'VMM').forEach(key => delete temp[key]);
  }

  return temp;
}

// 显示warning提示信息
function showWarningInfo(message: string) {
  elMessage({
    type: 'warning',
    message,
    icon: IconAlarm,
    customClass: 'el-message--warning',
    showClose: true,
    duration: 5000,
  });
}

function hasVncChange(): boolean {
  return (
    'VNC' in changeData.port1 ||
    'VNC' in changeData.port2 ||
    'VNC' in changeData.switch
  );
}

// 点保存按钮时打开提示框
function confirm() {
  if (hasVncChange()) {
    dialogConfig.content = traduction('SERVICE_VNC_PORT_CHANGE_MESSAGE');
  } else {
    dialogConfig.content = traduction('SERVICE_TIMESSAGE_CONTENT');
  }
  dialogRef.value.show();
}

// Dialog框关闭事件
function closeModal(reason: boolean) {
  if (reason) {
    isEdit.value = false;
    dialogRef.value.hide();
    savePortData();
  } else {
    dialogRef.value.hide();
  }
}

// 保存数据修改
function savePortData() {
  const param = cteateChangeParam();
  if (isLocked.value && Object.keys(param).length === 0) {
    return;
  }
  loading(true);
  disabled.value = true;
  setPortInfo(param)
    .then(res => {
      setStoreData('event', 'alertMessage', {
        type: 'success',
        message: traduction('COMMON_SUCCESS'),
      });

      checkHasModifyHttps(param, res);
    })
    .finally(() => {
      loading(false);
      init();
    });
}

// 检测是否修改了HTTP和HTTPS
function checkHasModifyHttps(param: any, res: any) {
  if (param && Object.keys(param).length > 0) {
    // 若有HTTP或HTTPS端口变更, 则延迟修改浏览器端口
    const protocol = self.window.location.protocol.toLowerCase().replace(':', '');
    if (
      (protocol === 'https' && param.HTTPS && param.HTTPS.Port) ||
      (protocol === 'http' && param.HTTP && param.HTTP.Port)
    ) {
      const httpPort = res.HTTP.Port;
      const httpsPort = res.HTTPS.Port;
      const port = protocol === 'https' ? httpsPort : httpPort;
      setTimeout(() => {
        self.window.location.port = port;
      }, 3000);
    }
  }
}

// 清空changeData
function clearChangeData() {
  Object.keys(changeData.port1).forEach(key => {
    delete changeData.port1[key];
  });
  Object.keys(changeData.port2).forEach(key => {
    delete changeData.port2[key];
  });
  Object.keys(changeData.switch).forEach(key => {
    delete changeData.switch[key];
  });
}

function dialogRMCPClose(val: boolean) {
  RMCPdialogRef.value.hide();
  tableData.value?.forEach(item => {
    if (item.name === dialogId) {
      if (!val) {
        item.enabledEdit = !item.enabledEdit;
      } else {
        if (item.enabled !== item.enabledEdit) {
          changeData.switch[item.name] = item.enabledEdit;
        } else {
          delete changeData.switch[item.name];
        }
      }
    }
  });
  computeSaveState();
}

function getShowData(res: IPortListItem[]): any {
  let arr = [] as any;
  res.forEach((item: any) => {
    const checkName = (item.name as string).replace(/\d+$/, '');
    if (checkSupported[checkName] || checkSupported[checkName] === undefined) {
      arr.push(item);
    }
  });
  return arr;
}

function init() {
  loading(true);
  getPortInfo()
    .then((res: IPortListItem[]) => {
      tableData.value = getShowData(res);
      total.value = tableData.value.length;
      clearChangeData();
    })
    .finally(() => {
      loading(false);
      if (tableData.value) {
        for (let item of tableData.value) {
          if (
            (item.name === 'IPMILANRMCP' || item.name === 'IPMILANRMCPPlus') &&
            item.enabled === true
          ) {
            showWarningInfo(traduction('SERVICE_OPEN_RMCP'));
            break;
          }
        }
      }
    });
}

onMounted(() => {
  init();
});
</script>

<template>
  <div class="root-container">
    <div class="right-container used-to-table">
      <h4 v-t="'SERVICE_PORT_INFORMATION'" class="page-right-title-level2"></h4>
      <div class="edit">
        <div class="port-buttons">
          <el-button
            v-if="!isEdit && !isLocked"
            id="portEdit"
            v-privil.security
            type="primary"
            @click="editPort(true)"
          >
            {{ $t('COMMON_EDIT') }}
          </el-button>
          <el-button
            v-if="isEdit"
            id="portSave"
            :disabled="isLocked || disabled"
            type="primary"
            @click="confirm()"
          >
            {{ $t('COMMON_SAVE') }}
          </el-button>
          <el-button v-if="isEdit" id="portCancel" @click="editPort(false)">
            {{ $t('COMMON_CANCEL') }}
          </el-button>
        </div>

        <div id="formPortId" class="table">
          <el-table
            v-addId.table="'tablePortId'"
            :data="tableData"
            :class="{ 'port-table-edit': isEdit }"
            resizable
            border
          >
            <!-- Name -->
            <el-table-column :prop="'name'" :label="$t('SERVICE')" :resizable="true">
              <template #default="scope">
                <span :id="'service' + scope.row.alias">{{ scope.row.label }}</span>
                <el-tooltip
                  v-if="scope.row.name === 'IPMILANRMCP'"
                  :content="$t('SERVICE_TIP_CONTENT2')"
                  :placement="'right'"
                  popper-class="port-service-tooltip-box"
                  trigger-keys
                >
                  <i class="icon-help ver-mid"></i>
                </el-tooltip>
                <el-tooltip
                  v-if="scope.row.name === 'IPMILANRMCPPlus'"
                  :content="$t('SERVICE_TIP_CONTENT')"
                  :placement="'right'"
                  popper-class="port-service-tooltip-box"
                  trigger-keys
                >
                  <i class="icon-help ver-mid"></i>
                </el-tooltip>
              </template>
            </el-table-column>

            <!-- 端口 -->
            <el-table-column :label="$t('SERVICE_PORT')" :resizable="true">
              <template #default="scope">
                <div v-if="!isEdit" :id="'portVal' + scope.row.alias">
                  {{ scope.row.port1 === 'undefined' ? '' : scope.row.port1 }}
                </div>
                <div v-if="isEdit && scope.row.port1 !== null">
                  <el-form
                    ref="port1Form"
                    :model="scope.row"
                    :rules="rules"
                    :validate-on-rule-change="false"
                  >
                    <el-form-item prop="port1Edit" class="input-form-item">
                      <div class="input-box">
                        <el-tooltip
                          :visible="scope.row.tipState1"
                          :content="$t('SERVICE_PORT_RANGES')"
                          :hide-after="0"
                          placement="top"
                          transition="none"
                          trigger-keys
                        >
                          <el-input
                            v-model="scope.row.port1Edit"
                            v-addId.input="scope.row.id1"
                            v-clearable
                            clearable
                            type="text"
                            @focus="scope.row.tipState1 = true"
                            @blur="scope.row.tipState1 = false"
                            @input="resetControlValue(scope.row, 1, scope.row.name, $event)"
                          >
                            <template #suffix>
                              <ErrorIcon />
                              <ClearableIcon />
                            </template>
                          </el-input>
                        </el-tooltip>
                      </div>
                      <span
                        v-t="'SERVICE_DEFAULT_VALUE'"
                        class="port-reset"
                        @click="port1Rest(scope.row)"
                      ></span>
                    </el-form-item>
                  </el-form>
                </div>
              </template>
            </el-table-column>

            <!-- 备用端口 -->
            <el-table-column :prop="'sparePort'" :label="$t('SERVICE_KVM_PORT2')" :resizable="true">
              <template #default="scope">
                <div v-if="!isEdit" :id="'portValStandby' + scope.row.alias">
                  {{ scope.row.port2 === 'undefined' ? '' : scope.row.port2 }}
                </div>
                <div v-if="isEdit && scope.row.port2 !== null">
                  <el-form
                    ref="port2Form"
                    :model="scope.row"
                    :rules="rules"
                    :validate-on-rule-change="false"
                  >
                    <el-form-item prop="port2Edit">
                      <el-tooltip
                        :visible="scope.row.tipState2"
                        :content="$t('SERVICE_PORT_RANGES')"
                        :hide-after="0"
                        placement="top"
                        trigger="focus"
                        transition="none"
                        trigger-keys
                      >
                        <el-input
                          v-model="scope.row.port2Edit"
                          v-addId.input="scope.row.id2"
                          v-clearable
                          type="text"
                          clearable
                          @focus="scope.row.tipState2 = true"
                          @blur="scope.row.tipState2 = false"
                          @input="resetControlValue(scope.row, 2, scope.row.name, $event)"
                        >
                          <template #suffix>
                            <ErrorIcon />
                            <ClearableIcon />
                          </template>
                        </el-input>
                      </el-tooltip>
                      <span
                        v-t="'SERVICE_DEFAULT_VALUE'"
                        class="port-reset"
                        @click="port2Rest(scope.row)"
                      ></span>
                    </el-form-item>
                  </el-form>
                </div>
              </template>
            </el-table-column>
            <!-- 状态 -->
            <el-table-column :prop="'enabled'" :label="$t('SERVICE_STATUS')" :resizable="true">
              <template #default="scope">
                <div v-if="!isEdit">
                  <el-tag
                    v-if="scope.row.enabled"
                    :id="'status' + scope.row.alias"
                    type="success"
                    size="small"
                  >
                    {{ $t('SERVICE_ENABLED') }}
                  </el-tag>
                  <el-tag
                    v-if="!scope.row.enabled"
                    :id="'status' + scope.row.alias"
                    type="info"
                    size="small"
                  >
                    {{ $t('SERVICE_DISABLED') }}
                  </el-tag>
                </div>
                <div v-if="isEdit">
                  <el-switch
                    :id="'switch_' + scope.row.name"
                    v-model="scope.row.enabledEdit"
                    :active-value="true"
                    :inactive-value="false"
                    :before-change="beforeStateChange(scope.row)"
                    @change="switchChange(scope.row)"
                  />
                </div>
              </template>
            </el-table-column>
            <template #empty>
              <TableNoData />
            </template>
          </el-table>

          <!-- 分页 -->
          <el-pagination
            v-if="true"
            v-model:currentPage="currentPage"
            v-addId.pagination="'portPagination'"
            :page-sizes="[15, 30, 50]"
            :page-size="pageSize"
            layout="total, sizes, prev, pager, next, jumper"
            :total="total"
            @size-change="handleSizeChange"
          />
        </div>
      </div>
    </div>
  </div>
  <Dialog ref="RMCPdialogRef" :config="RMCPdiaginfo" @close="dialogRMCPClose"></Dialog>
  <Dialog ref="dialogRef" :config="dialogConfig" @close="closeModal" />
</template>

<style lang="scss" scoped>
.right-container {
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;

  .edit {
    padding-top: 16px;
    flex: 1;
    display: flex;
    flex-direction: column;

    .table {
      flex: 1;
      display: flex;
      flex-direction: column;
    }

    .port-buttons {
      margin-bottom: 16px;
    }
  }

  :deep(.el-pagination) {
    margin-top: 16px;
  }
}

.ver-mid {
  vertical-align: middle;
  cursor: pointer;
}

.port-ipt {
  width: 120px;
}

.icon-help {
  font-size: 16px;
  &:hover::before {
    color: $APP-COLOR-HOVER;
  }
}

.port-reset {
  position: absolute;
  left: 128px;
  top: 8px;
  color: $APP-COLOR-ACTIVE;
  cursor: pointer;
  font-size: 12px;
  &:hover {
    color: $APP-COLOR-HOVER;
  }
}

.port {
  width: 120px;
}

:deep(.el-tag) {
  min-width: 64px !important;
  height: 16px;
}
:deep(.el-tag--info) {
  background-color: var(--o-text-color-tertiary) !important;
}
:deep(.el-form-item__error) {
  position: static;
  width: 100%;
  padding-bottom: 0;
}

:deep(.el-form-item) {
  margin-bottom: 0 !important;
}
:deep(.el-form-item__content) {
  line-height: 16px;
}
:deep(.el-input__suffix) {
  align-items: center;
}

:deep(.el-input--suffix) {
  width: 120px !important;
}

:deep(.el-table__body-wrapper) {
  .el-table__body {
    .el-table__cell {
      padding: 8px 10px;
      .cell {
        line-height: 32px;
      }
    }
  }
}
</style>

<style lang="scss">
.port-service-tooltip-box {
  max-width: 382px;
}
</style>
