<script lang="ts" setup>
import useStore from '@/stores';
import { useRouter } from 'vue-router';
import { traduction } from '@/utils/language';
import { reactive, ref, nextTick, computed } from 'vue';
import { initRules } from '@/validators/password-rules';
import { IVncData } from '@/model/Service/vnc-interface';
import { showElMessage, compareObjectEqual } from '@/utils/utils';
import { rangeVerification, strVerification } from '@/validators/validation-functions';
import { getVncData, editVncData, setVncListWithoutPassword, setVncList } from './vnc.server';
import { UserPrivil } from '@/model/base-enum';
import { checkPrivil } from '@/apps/app-bmc/router/routes';

import Lock from '@/components/Lock/Lock.vue';
import ErrorIcon from '@/components/ErrorIcon/ErrorIcon.vue';
import LoginRules from '@/components/LoginRules/LoginRules.vue';
import GlobalStoreService from '@/services/gloabal-store-service';
import ClearableIcon from '@/components/ClearableIcon/ClearableIcon.vue';
import PullDownTriangle from '@/components/PullDownTriangle/PullDownTriangle.vue';
import SecondPassword from '@/components/SecondPassword/SecondPassword.vue';
import ComplexPopoverContentOfList from '@/components/ComplexPopoverContent/ComplexPopoverContentOfList.vue';
import { getStoreData } from '@/utils/composition';

const globalStoreService = new GlobalStoreService();
const successMsg = traduction('COMMON_SUCCESS');
const errorMsg = traduction('COMMON_FAILED');
const store = useStore();
const router = useRouter();

// 用户配置权限
const isConfigureUser = checkPrivil(UserPrivil.userConfig);
// 安全配置权限
const isOemSecurityMgmtUser = checkPrivil(UserPrivil.securityConfig);
// 远程控制权限
const isOemKvmUser = checkPrivil(UserPrivil.remoteControl);
// 常规配置权限
const isBaseConfig = checkPrivil(UserPrivil.baseConfig);

const isSystemLock = computed(() => {
  return store.state.glob.systemLocked;
});

// disabled状态，分为两部分，VNC使能和端口是一部分，其他的是另外一部分
const disabledState = computed(() => {
  return {
    enableSwitchAndPort: !isOemSecurityMgmtUser || isSystemLock.value,
    enableOutTime: !isBaseConfig || isSystemLock.value,
    others: !isOemKvmUser || isSystemLock.value,
  };
});

// 是否免密登录
const nopwd = getStoreData('loct', 'nopwd');

// 获取数据完成的情况
let getDataRes = {
  vncData: false,
  ruleData: false,
};
const keyboardLayoutList = [
  {
    value: 'en',
    label: traduction('HOME_EN_KEYBOARD'),
  },
  {
    value: 'jp',
    label: traduction('SERVICE_VNC_KEY_LABEL_J'),
  },
  {
    value: 'de',
    label: traduction('HOME_DE_KEYBOARD'),
  },
];

const VNCPasswordRange = [1, 8];
// 保存按钮状态
let saveBtnState = ref(false);
let passwordDialog = ref();

const popoverVisible = reactive({
  Port: false,
  SessionTimeoutMinutes: false,
  VNCPassword: false,
});

// 初始值
let oldDatas: IVncData = {};

// 编辑中的数据-显示数据
let editData: IVncData = reactive({
  Enabled: false,
  DisableKeyboardDuringBiosStartup: false,
  Port: '',
  SessionTimeoutMinutes: '',
  KeyboardLayout: '',
  VNCPassword: '',
  sureVNCPassword: '',
  PasswordValidityDays: '',
  LoginRuleInfo: [],
  LoginRule: [],
  SSLEncryptionEnabled: false,
  MaximumNumberOfSessions: '',
  NumberOfActiveSessions: 0,
  ActivatedSessionsType: '',
  PasswordComplexityCheckEnabled: false,
});

// 表单校验结果
let validateResult = {};

const ruleFormRef = ref();

// 校验规则
let rules = reactive({
  Port: {
    type: 'number',
    required: true,
    isInteger: true,
    min: 1,
    max: 65535,
    message: traduction('SERVICE_PORT_RANGES'),
    validator: rangeVerification,
    trigger: 'blur',
  },
  SessionTimeoutMinutes: {
    type: 'number',
    required: true,
    isInteger: true,
    min: 0,
    max: 480,
    message: traduction('SERVICE_VNC_TIMEOUT_BLUR'),
    validator: rangeVerification,
    trigger: 'blur',
  },
  VNCPassword: {},
  sureVNCPassword: {
    type: 'text',
    required: false,
    containsEmptyString: true,
    equals: {
      aimObj: editData,
      aimObjKey: 'VNCPassword',
    },
    validator: strVerification,
    message: traduction('COMMON_FORMAT_PASSWORD_NO_EQUALS'),
    trigger: 'blur',
  },
});

// 点击恢复默认值
function setDefaultValue() {
  editData.Port = '5900';
  ruleFormRef.value.validateField('Port');
}

// 输入框 发生input 事件
function input(key: string, value: string) {
  // 调用校验方法校验数据是否能通过，因为当前校验方式是blur，在input事件触发时不会触发校验，
  // 但是为了在输入的时候控制保存按钮的状态，需要手动去触发校验函数获取校验结果，进而控制保存按钮状态
  validateResult[key] = rules[key].validator(rules[key], editData[key], () => {});
  /**
   * 如果是vnc密码输入框，还需要去校验确认密码,下面是需要校验的情形:
   * 1. 当确认密码输入框有值时
   * 2. 当VNC密码输入框和确认VNC密码输入框都没有值
   */
  if (
    key === 'VNCPassword' &&
    (editData.sureVNCPassword || (!editData.VNCPassword && !editData.sureVNCPassword))
  ) {
    ruleFormRef.value.validateField('sureVNCPassword');
  }

  nextTick(() => {
    setSaveBtnState();
  });
}

// 登陆规则发生修改
function loginRuleChange(res: any) {
  let { LoginRule } = editData;
  if (LoginRule) {
    LoginRule.splice(0);
    for (let key in res) {
      if (res[key]) {
        LoginRule.push(key);
      }
    }
    setSaveBtnState();
  }
}

// 表单校验发生时 - 控制保存按钮状态 state:校验结果
function validate(key: string, state: boolean) {
  validateResult[key] = state;
  nextTick(() => {
    setSaveBtnState();
  });
}

function focus(key: string) {
  popoverVisible[key] = true;
}

function blur(key: string) {
  popoverVisible[key] = false;
}

function clear(key: string) {
  // 如果没有focus，那么这个地方需要手动调用一次校验
  if (!popoverVisible[key]) {
    ruleFormRef.value.validateField(key);
  }
}

// 设置保存按钮状态
function setSaveBtnState() {
  for (let key in validateResult) {
    // 任意一个校验失败
    if (!validateResult[key]) {
      saveBtnState.value = false;
      return;
    }
  }

  // VNC密码和确认密码不相等
  const { VNCPassword, sureVNCPassword } = editData;
  if (VNCPassword !== sureVNCPassword) {
    saveBtnState.value = false;
    return;
  }
  // 校验成功后，进行初始值和修改值的对比，看是否发生修改
  saveBtnState.value = !compareObjectEqual(oldDatas, editData, [
    'LoginRuleInfo',
    'ActivatedSessionsType',
  ]);
}

// 获取请求参数
function getParams() {
  const params: any = {};
  if (editData.Enabled !== oldDatas.Enabled) {
    params.Enabled = editData.Enabled;
  }

  if (editData.DisableKeyboardDuringBiosStartup !== oldDatas.DisableKeyboardDuringBiosStartup) {
    params.DisableKeyboardDuringBiosStartup = editData.DisableKeyboardDuringBiosStartup;
  }

  if (editData.Port !== oldDatas.Port) {
    params.Port = Number(editData.Port);
  }

  if (editData.SessionTimeoutMinutes !== oldDatas.SessionTimeoutMinutes) {
    params.SessionTimeoutMinutes = Number(editData.SessionTimeoutMinutes);
  }

  if (editData.KeyboardLayout !== oldDatas.KeyboardLayout) {
    params.KeyboardLayout = editData.KeyboardLayout;
  }

  if (!compareObjectEqual(editData.LoginRule, oldDatas.LoginRule)) {
    params.LoginRule = editData.LoginRule;
  }

  if (editData.SSLEncryptionEnabled !== oldDatas.SSLEncryptionEnabled) {
    params.SSLEncryptionEnabled = editData.SSLEncryptionEnabled;
  }
  return params;
}

// 点击保存
function submitForm() {
  // 没有输入VNC密码的时候
  if (editData.VNCPassword === '') {
    editVncData(getParams())
      .then((data: any) => {
        initShowData(data);
        showElMessage('success', successMsg);
        saveBtnState.value = false;
      })
      .catch((error: any) => {
        const code = error?.data?.error[0]?.code;
        if (code) {
          const errorMessage = code + '.errorMessage';
          showElMessage('error', traduction(errorMessage));
          return;
        }
        showElMessage('error', errorMsg);
      });
  } else {
    if (nopwd) {
      setVncListWithoutPassword(getParams(), {
        VNCPassword: editData.VNCPassword,
      })
        .then(() => {
          getData();
          showElMessage('success', successMsg);
          saveBtnState.value = false;
        })
        .catch((error: any) => {
          const code = error?.data?.error[0]?.code;
          if (code) {
            const errorMessage = code + '.errorMessage';
            showElMessage('error', traduction(errorMessage));
            return;
          }
          showElMessage('error', errorMsg);
        });
    } else {
      //  修改弹窗显示状态
      passwordDialog.value.show();
    }
  }
}

// 点击弹窗中的保存按钮 value:输入框中的密码值
function interPassworSave(res: { reason: boolean; password: string }) {
  if (res.reason) {
    setVncList(
      getParams(),
      {
        VNCPassword: editData.VNCPassword,
      },
      res.password,
    )
      .then(() => {
        getData();
        showElMessage('success', successMsg);
        passwordDialog.value.hide();
        saveBtnState.value = false;
      })
      .catch((err: any) => {
        const errorId = err?.data?.error?.[0]?.code || '';
        passwordDialog.value.setErrorId();
        passwordDialog.value.clearPassword();
        if (errorId === 'PasswordPatternCheckFailed') {
          passwordDialog.value.hide();
        }
      });
  } else {
    passwordDialog.value.hide();
  }
}

// 点击活跃用户数量
function toOnlineUser() {
  const num = editData.NumberOfActiveSessions;
  if (num && num > 0 && isConfigureUser) {
    router.push('/navigate/user/online-users');
  }
}

// 初始化展示数据
function initShowData(data: any) {
  if (!data) {
    return;
  }
  data.VNCPassword = '';
  data.sureVNCPassword = '';
  // 设置密码检查规则
  rules.VNCPassword = initRules(data.PasswordComplexityCheckEnabled);
  const activeNum = data.NumberOfActiveSessions;
  if (activeNum || activeNum === 0) {
    data.NumberOfActiveSessions = Number(activeNum);
  } else {
    data.NumberOfActiveSessions = 0;
  }

  if (data.PasswordValidityDays === null) {
    data.PasswordValidityDays = traduction('SERVICE_VNC_INDEFINITE');
  } else if (data.PasswordValidityDays === 0) {
    data.PasswordValidityDays = traduction('SERVICE_LONG_TIME');
  }

  let port = data.Port;
  if (port || port === 0) {
    data.Port = port.toString();
  }

  let sessionTimeoutMinutes = data.SessionTimeoutMinutes;
  if (sessionTimeoutMinutes || sessionTimeoutMinutes === 0) {
    data.SessionTimeoutMinutes = sessionTimeoutMinutes.toString();
  }

  oldDatas = JSON.parse(JSON.stringify(data));
  Object.assign(editData, { ...data });
  getDataRes.vncData = true;
  globalStoreService.setValue('isLoading', false);
}

// 获取数据
function getData() {
  globalStoreService.setValue('isLoading', true);
  getVncData()
    .then((data: any) => {
      initShowData(data);
    })
    .catch(err => {
      getDataRes.vncData = true;
      globalStoreService.setValue('isLoading', false);
    });
}

// 获取数据
nextTick(()=>{
  getData();
});
</script>

<template>
  <div id="vncView" class="vnc-box">
    <!-- 内容区域 -->
    <div class="vnc-content">
      <!-- 主要内容区域 -->
      <div class="content-details">
        <el-form
          ref="ruleFormRef"
          :model="editData"
          :rules="rules"
          label-position="left"
          label-width="auto"
          :validate-on-rule-change="false"
          @validate="validate"
        >
          <!-- VNC使能 -->
          <el-form-item
            :label="$t('SERVICE_VNC_ABLE_LABEL')"
            class="item have-right-text-item special-item"
          >
            <el-switch
              id="vncEnable"
              v-model="editData.Enabled"
              :disabled="disabledState.enableSwitchAndPort"
              @change="setSaveBtnState"
            />
            <div v-show="editData.Enabled" id="vncAlert" class="right-warn-tip">
              {{ $t('SERVICE_VNC_SECURITY_TIP') }}
            </div>
          </el-form-item>

          <!-- VNC热能使能 -->
          <el-form-item
            :label="$t('SERVICE_VNC_DISABLE_LABEL')"
            class="item have-right-text-item special-item"
          >
            <el-switch
              id="vncHotEnable"
              v-model="editData.DisableKeyboardDuringBiosStartup"
              :disabled="disabledState.others"
              @change="setSaveBtnState"
            />
          </el-form-item>

          <!-- 端口 -->
          <el-form-item :label="$t('SERVICE_PORT')" prop="Port" class="item have-right-text-item">
            <el-popover
              v-model:visible="popoverVisible.Port"
              popper-class="no-wrap-popover"
              placement="top"
              :teleported="false"
              trigger="focus"
              trigger-keys
            >
              <span id="vncPortTip">{{ $t('VALIDTOR_RANGE') }}</span>
              <template #reference>
                <el-input
                  v-model="editData.Port"
                  v-addId.input="'vncPort'"
                  v-clearable
                  clearable
                  :disabled="disabledState.enableSwitchAndPort"
                  type="text"
                  @focus="focus('Port')"
                  @blur="blur('Port')"
                  @input="input('Port', $event)"
                  @clear="clear('Port')"
                >
                  <template #suffix>
                    <ErrorIcon />
                    <ClearableIcon />
                  </template>
                </el-input>
              </template>
            </el-popover>

            <div
              v-if="isOemSecurityMgmtUser && !isSystemLock"
              id="vncResetPort"
              class="right-default-tip"
              @click="setDefaultValue"
            >
              {{ $t('SERVICE_DEFAULT_VALUE') }}
            </div>
          </el-form-item>

          <!-- 超时时长(分钟) -->
          <el-form-item
            :label="$t('SERVICE_TIME_OUT_MINUTES')"
            prop="SessionTimeoutMinutes"
            class="item have-right-text-item"
          >
            <el-popover
              v-model:visible="popoverVisible.SessionTimeoutMinutes"
              popper-class="no-wrap-popover"
              placement="right"
              trigger="focus"
              trigger-keys
            >
              <span id="vncTimeoutTip">{{ $t('SERVICE_VNC_TIMEOUT_TIP') }}</span>
              <template #reference>
                <el-input
                  v-model="editData.SessionTimeoutMinutes"
                  v-addId.input="'vncTimeout'"
                  v-clearable
                  clearable
                  type="text"
                  :disabled="disabledState.enableOutTime"
                  @focus="focus('SessionTimeoutMinutes')"
                  @blur="blur('SessionTimeoutMinutes')"
                  @input="input('SessionTimeoutMinutes', $event)"
                  @clear="clear('SessionTimeoutMinutes')"
                >
                  <template #suffix>
                    <ErrorIcon />
                    <ClearableIcon />
                  </template>
                </el-input>
              </template>
            </el-popover>
          </el-form-item>

          <!-- 键盘布局 -->
          <el-form-item :label="$t('SERVICE_VNC_KEYBOARD_LAYOUT')" class="item">
            <el-select
              v-model="editData.KeyboardLayout"
              v-addId.select="'keyboardLayout'"
              :teleported="false"
              :disabled="disabledState.others"
              :suffix-icon="PullDownTriangle"
              @change="setSaveBtnState"
            >
              <el-option
                v-for="item in keyboardLayoutList"
                :key="item.value"
                :label="item.label"
                :value="item.value"
                :name="item.value"
              />
            </el-select>
          </el-form-item>

          <!-- VNC密码 -->
          <el-form-item
            :label="$t('SERVICE_VNC_PASSWORD')"
            prop="VNCPassword"
            class="item have-right-text-item"
          >
            <el-popover
              v-model:visible="popoverVisible.VNCPassword"
              popper-class="no-wrap-popover"
              :placement="'right-start'"
              trigger="focus"
              trigger-keys
            >
              <!-- 没有开启密码检查-popover内容 -->
              <span v-if="!editData.PasswordComplexityCheckEnabled" id="vncPasswordPopper">
                {{ rules.VNCPassword['tipText'] }}
              </span>
              <!-- 开启密码检查-popover内容 -->
              <ComplexPopoverContentOfList
                v-if="editData.PasswordComplexityCheckEnabled"
                id="vncPasswordPopper"
                :data="rules.VNCPassword['verificationList']"
              />

              <template #reference>
                <el-input
                  v-model="editData.VNCPassword"
                  v-addId.input="'vncPassword'"
                  v-clearable
                  clearable
                  maxlength="8"
                  type="password"
                  autocomplete="new-password"
                  :disabled="disabledState.others"
                  @focus="focus('VNCPassword')"
                  @blur="blur('VNCPassword')"
                  @input="input('VNCPassword', $event)"
                  @clear="clear('VNCPassword')"
                >
                  <template #suffix>
                    <ErrorIcon />
                    <ClearableIcon />
                  </template>
                </el-input>
              </template>
            </el-popover>
          </el-form-item>

          <!-- 确认VNC密码 -->
          <el-form-item
            :label="$t('SERVICE_VNC_SURE_PASSWORD')"
            prop="sureVNCPassword"
            class="item item-sure-password have-right-text-item"
          >
            <el-input
              v-model="editData.sureVNCPassword"
              v-addId.input="'vncPwdConfirm'"
              v-clearable
              clearable
              maxlength="8"
              type="password"
              autocomplete="new-password"
              :disabled="disabledState.others"
              @focus="focus('sureVNCPassword')"
              @blur="blur('sureVNCPassword')"
              @input="input('sureVNCPassword', $event)"
              @clear="clear('sureVNCPassword')"
            >
              <template #suffix>
                <ErrorIcon />
                <ClearableIcon />
              </template>
            </el-input>
          </el-form-item>

          <!--  密码有效期(天) -->
          <el-form-item :label="$t('SERVICE_SERVICE_VNC_PASSWORD_DATE')" class="item special-item">
            <div id="vncPwdData" class="value">{{ editData.PasswordValidityDays }}</div>
          </el-form-item>

          <!--  登录规则 -->
          <el-form-item :label="$t('SERVICE_VNC_LOGIN_RULE')" class="item rule-item">
            <LoginRules
              :check-list="editData.LoginRule"
              :rule-data-list="editData.LoginRuleInfo"
              @login-rule-change="loginRuleChange"
            />
          </el-form-item>

          <!--  SSL加密 -->
          <el-form-item :label="$t('SERVICE_VNC_SSI')" class="item special-item">
            <el-switch
              id="vncSSL"
              v-model="editData.SSLEncryptionEnabled"
              :disabled="disabledState.others"
              @change="setSaveBtnState"
            />
            <div
              v-if="editData.Enabled && !editData.SSLEncryptionEnabled"
              id="vncSSLAlert"
              class="right-warn-tip"
            >
              {{ $t('SERVICE_VNC_SSL_SECURITY_TIP') }}
            </div>
          </el-form-item>

          <!--  最大会话 -->
          <el-form-item :label="$t('SERVICE_VNC_MAX_SESSION')" class="item special-item">
            <div id="vncSession" class="value">{{ editData.MaximumNumberOfSessions }}</div>
          </el-form-item>

          <!--  活跃会话 -->
          <el-form-item :label="$t('SERVICE_ACTIVE_SESSIONS')" class="item special-item">
            <div
              id="vncActive"
              :class="['value', editData.NumberOfActiveSessions ? 'active-conversation' : '']"
              @click="toOnlineUser"
            >
              {{ editData.NumberOfActiveSessions }}
            </div>
          </el-form-item>

          <!-- 保存 -->
          <el-form-item v-if="isOemSecurityMgmtUser || isOemKvmUser || isBaseConfig" label=" ">
            <el-button id="vncButton" :disabled="!saveBtnState" type="primary" @click="submitForm">
              {{ $t('COMMON_SAVE') }}
            </el-button>
          </el-form-item>
        </el-form>

        <!-- 点击保存的弹窗 输入登陆密码 -->
        <SecondPassword ref="passwordDialog" @close="interPassworSave" />
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.page-title {
  padding: 16px 0;
  font-size: 18px;
  color: var(--o-text-color-primary);
  line-height: 24px;
  font-weight: bolder;
}

.vnc-box {
  padding-right: 24px;
  color: var(--o-text-color-secondary);
  position: relative;

  :deep(#lock) {
    margin-right: 0;
  }

  .vnc-content {
    padding: 24px;
    border-radius: 4px;
    background-color: var(--o-bg-color-base);

    .content-details {
      display: flex;
      flex-direction: column;

      .item {
        margin-bottom: 24px;

        .right-warn-tip {
          margin-left: 8px;
          color: var(--o-color-major);
        }

        .right-default-tip {
          margin-left: 8px;
          color: var(--o-color-primary);
          cursor: pointer;

          &:hover {
            color: var(--o-color-primary-secondary);
          }
        }

        .el-input,
        .el-select {
          width: var(--el-select-and-input-width);
        }

        .active-conversation {
          cursor: pointer;
          color: var(--o-color-primary);
        }
      }

      :deep(.special-item) {
        margin-bottom: 24px;
        height: 16px;

        .value,
        .el-form-item__label,
        .el-form-item__content {
          line-height: 16px;
          padding-top: 0;
          padding-bottom: 0;
        }
      }

      .rule-item {
        :deep(.el-form-item__label-wrap) {
          .el-form-item__label {
            padding-top: 0;
          }
        }
      }

      :deep(.el-form-item__label) {
        white-space: nowrap;
      }

      .el-form-item:nth-last-child(1) {
        margin-bottom: 0;
      }

      :deep(.have-right-text-item) {
        .el-form-item__content {
          display: flex;
          align-items: center;
        }
      }

      :deep(.el-form-item__label::before) {
        display: none;
      }

      :deep(.el-select__caret) {
        margin-right: 0;
      }
    }

    :deep(.el-input__inner::-webkit-input-placeholder) {
      font-size: 12px !important;
    }

    :deep(.el-popper) {
      min-width: auto !important;
      width: auto !important;
    }
  }
}

.no-wrap-popover{
  max-width: 200px !important;
}
</style>
