<script lang="ts" setup>
import { inject, nextTick, onMounted, PropType, reactive, Ref, ref, toRaw, watch } from 'vue';
import { traduction } from '@/utils/language';
import { ILdap, ILdapUserGroup } from '@/model/Users/ldap-interface';
import { saveLdapGroup } from '../services/ldap.service';
import { SecondAuthorityFail } from '../../models/model';
import { getStoreData, loading, showFailedMessage, showSuccessMessage } from '@/utils/composition';
import { BaseValidators } from '@/validators/base-validators';
import ErrorIcon from '@/components/ErrorIcon/ErrorIcon.vue';
import ClearableIcon from '@/components/ClearableIcon/ClearableIcon.vue';
import LoginRules from '@/components/LoginRules/LoginRules.vue';
import Schema from 'async-validator';
import PullDownTriangle from '@/components/PullDownTriangle/PullDownTriangle.vue';

const ldapData: any = inject('ldapData');

const isNoPwd = getStoreData('loct', 'nopwd');
const pwdMaxLen = getStoreData('loct', 'pml');
// 选中的登录规则
const checkList: Ref<string[]> = ref([]);
// row表示传入的要编辑的组数据，LDAP、KRB用户组本质上新增和编辑没有任何区别，后端固定存在5个组用户，删除时，只是将某个组用户数据清空重新初始化。
const props = defineProps({
  data: {
    type: Object as PropType<ILdap>,
    required: true,
    default: () => {
      return {};
    },
  },
});
// 声明对外暴露的组件方法
defineExpose({
  save: () => {
    saveGroup();
  },
});

const groupFolderState = ref(false);
const rules: any = {
  groupName: [
    BaseValidators.Required({ message: traduction('VALIDTOR_FORMAT_ERROR') }),
    BaseValidators.NotAllWhiteSpace(),
    BaseValidators.MaxLength255(),
  ],
  groupFolder: [BaseValidators.MaxLength255()],
};
const formSchema = new Schema(rules);
const formState = ref(true);

const emits = defineEmits(['close', 'enable', 'disable']);
// changeData记录哪些数据有变动
const changeData = {};

// 登录接口
const loginInterface = ['Web', 'Redfish', 'SSH'];
const roleOptions = [
  {
    value: 'Administrator',
    label: traduction('COMMON_ROLE_ADMINISTRATOR'),
  },
  {
    value: 'Operator',
    label: traduction('COMMON_ROLE_OPERATOR'),
  },
  {
    value: 'CommonUser',
    label: traduction('COMMON_ROLE_COMMONUSER'),
  },
  {
    value: 'CustomRole1',
    label: traduction('COMMON_ROLE_CUSTOMROLE1'),
  },
  {
    value: 'CustomRole2',
    label: traduction('COMMON_ROLE_CUSTOMROLE2'),
  },
  {
    value: 'CustomRole3',
    label: traduction('COMMON_ROLE_CUSTOMROLE3'),
  },
  {
    value: 'CustomRole4',
    label: traduction('COMMON_ROLE_CUSTOMROLE4'),
  },
];

// 组件绑定数据
const secondFailedMsg = ref('');
const groupInfo = reactive({
  groupName: '',
  groupFolder: '',
  password: '',
  role: roleOptions[2].value,
  loginRule: [],
  interface: [...loginInterface],
});
let baseData: any = null;

// 计算保存按钮的状态
function computeSaveState() {
  const isChange = Object.keys(changeData).length > 0;
  const isPwdValid = isNoPwd || groupInfo.password.length > 0;
  const state = !(isPwdValid && isChange && formState.value);
  if (state) {
    emits('disable');
  } else {
    emits('enable');
  }
}

// 记录数据变化的字段
function recordDataChange(key: string, valueTemp: any) {
  let value = valueTemp;
  const baseInfo = JSON.parse(baseData);
  let _value = baseInfo[key];
  if (typeof value !== 'string') {
    value = value.sort().join(',');
  }
  if (typeof _value !== 'string') {
    _value = _value.sort().join(',');
  }
  if (_value !== value) {
    changeData[key] = true;
  } else {
    delete changeData[key];
  }
}

// 登录规则变更事件
function recordLoginRuleChange(rulesList: any) {
  const ruleArr: any[] = [];
  Object.keys(rulesList).forEach(key => {
    if (rulesList[key]) {
      ruleArr.push(key);
    }
  });
  groupInfo.loginRule.length = 0;
  ruleArr.forEach(item => {
    groupInfo.loginRule.push(item as never);
  });
  recordDataChange('loginRule', ruleArr);
}

// 自定义输入框内容变化时，更新绑定数据的值（resetControlValue，resetPwd）
function resetControlValue(key: string, value: string) {
  formSchema.validate(groupInfo, (errors, fields) => {
    if (errors) {
      formState.value = false;
    } else {
      formState.value = true;
    }
  });

  // 密码输入时，清除密码出错信息
  if (key === 'password') {
    secondFailedMsg.value = '';
  }

  recordDataChange(key, value);
  computeSaveState();
}

// 更新组件的值
function reInitData(data: ILdapUserGroup) {
  const _data = JSON.parse(JSON.stringify(toRaw(data)));
  groupInfo.groupName = _data.Name;
  groupInfo.password = '';
  secondFailedMsg.value = '';

  if (ldapData.type === 'add') {
    groupInfo.groupName = '';
    groupInfo.groupFolder = '';
    groupInfo.interface = [...loginInterface];
    groupInfo.role = roleOptions[2].value;
    checkList.value = [];
  } else {
    const roleId = roleOptions.filter(item => item.value === _data.RoleID)[0]?.value;
    groupInfo.groupFolder = _data.Folder;
    groupInfo.role = roleId;
    groupInfo.interface = _data.LoginInterface;
    groupInfo.loginRule = _data.LoginRule as never[];
    checkList.value = _data.LoginRule;
  }

  // 清除变更对象
  Object.keys(changeData).forEach(key => {
    delete changeData[key];
  });

  baseData = JSON.stringify(toRaw(groupInfo));
}

// 保存组数据
function saveGroup() {
  let ldapGroupParams = { LdapGroup: [] };
  const emptyData = fillEmptyData();
  let param: { [key: string]: any } = {};
  ldapGroupParams.LdapGroup.push(...emptyData);
  if (ldapData.type === 'add') {
    // 新增时，添加全部参数
    param.Name = groupInfo.groupName.trim();
    param.Folder = groupInfo.groupFolder.trim();
    param.LoginInterface = groupInfo.interface;
    param.LoginRule = groupInfo.loginRule;
    param.RoleID = groupInfo.role;
  } else {
    // 编辑时，有变化的字段才添加进参数
    param = createParam();
  }
  ldapGroupParams.LdapGroup.push(param as never);

  loading(true);
  emits('disable');
  saveLdapGroup(props.data.Url?.control as string, ldapGroupParams, groupInfo.password)
    .then(
      () => {
        showSuccessMessage();
        emits('close');
      },
      error => {
        groupInfo.password = '';
        const errorCode = error.data.error[0].code;
        // 二次认证失败时，提示密码错误
        if (errorCode === SecondAuthorityFail.REAUTHFAILED ||
      errorCode === SecondAuthorityFail.AUTHORIZATIONFAILED) {
          resolveSecondAuthFailed(errorCode);
        } else {
          showFailedMessage();
        }
      },
    )
    .finally(() => {
      loading(false);
    });
}

// 处理二次认证错误的数据重置操作
function resolveSecondAuthFailed(errorId: string | undefined) {
  if (
    errorId === SecondAuthorityFail.AUTHORIZATIONFAILED ||
    errorId === SecondAuthorityFail.REAUTHFAILED
  ) {
    groupInfo.password = '';
    emits('disable');
    nextTick(() => {
      secondFailedMsg.value = traduction('COMMON_SECONDPWD_ERROR');
    });
  }
}

// 根据当前row的位置，填充空对象
function fillEmptyData() {
  const arr: never[] = [];
  let position = 0;
  props.data.LdapGroup.forEach((item: any, index: number) => {
    if (item.ID === ldapData?.row?.ID) {
      position = index;
    }
  });
  while (position > 0) {
    arr.push({} as never);
    position--;
  }
  return arr;
}

// 生成编辑状态下的参数对象
function createParam() {
  const param: any = {};
  if (changeData['groupName']) {
    param.Name = groupInfo.groupName.trim();
  }
  if (changeData['groupFolder']) {
    param.Folder = groupInfo.groupFolder.trim();
  }
  if (changeData['role']) {
    param.RoleID = groupInfo.role;
  }
  if (changeData['loginRule']) {
    param.LoginRule = groupInfo.loginRule;
  }
  if (changeData['interface']) {
    param.LoginInterface = groupInfo.interface;
  }
  return param;
}

// 组件挂载后，赋值组件各控件的值
onMounted(() => {
  reInitData(ldapData.row);
});

// 监听选中的row，变化时更新组件数据，并重设二次认证密码
watch(
  () => ldapData,
  (val: any) => {
    reInitData(val.row);
  },
  { deep: true },
);
</script>

<template>
  <div id="ldapGroupDeatils" class="root-container">
    <el-form
      ref="groupFormRef"
      :model="groupInfo"
      :rules="rules"
      :validate-on-rule-change="false"
      label-position="left"
      label-width="auto"
    >
      <!-- 组名 -->
      <el-form-item prop="groupName" :label="$t('COMMON_GROUP')" class="is-required">
        <el-input
          id="groupName"
          v-model="groupInfo.groupName"
          v-clearable
          type="text"
          clearable
          @input="resetControlValue('groupName', $event)"
        >
          <template #suffix>
            <ErrorIcon />
            <ClearableIcon />
          </template>
        </el-input>
      </el-form-item>

      <!-- 组应用文件夹 -->
      <el-form-item :label="$t('COMMON_GROUP_FOLDER_NAME')" prop="groupFolder">
        <el-popover
          v-model:visible="groupFolderState"
          :content="$t('COMMON_GROUP_FOLDER_TIP')"
          popper-class="ldap-group-popover"
          width="320px"
          placement="top"
          trigger="focus"
          trigger-keys
        >
          <template #reference>
            <el-input
              id="ldapGroupUserFolder"
              v-model="groupInfo.groupFolder"
              v-clearable
              clearable
              type="text"
              @input="resetControlValue('groupFolder', $event)"
              @focus="groupFolderState = true"
              @blur="groupFolderState = false"
            >
              <template #suffix>
                <ErrorIcon />
                <ClearableIcon />
              </template>
            </el-input>
          </template>
        </el-popover>
      </el-form-item>

      <!-- 角色 -->
      <el-form-item :label="$t('COMMON_ROLE')">
        <el-select
          v-model="groupInfo.role"
          v-addId.select="'roleList'"
          :teleported="false"
          :suffix-icon="PullDownTriangle"
          @change="recordDataChange('role', groupInfo.role)"
        >
          <el-option
            v-for="item in roleOptions"
            :id="'role_' + item.value"
            :key="item.value"
            :value="item.value"
            :label="item.label"
          ></el-option>
        </el-select>
      </el-form-item>
      <!-- 登录规则 -->
      <el-form-item :label="$t('COMMON_LOGIN_RULE')" class="ldap-form-rule">
        <LoginRules
          :show-type="'pullDown'"
          :check-list="checkList"
          @login-rule-change="recordLoginRuleChange"
        />
      </el-form-item>
      <!-- 登录接口 -->
      <el-form-item :label="$t('COMMON_LOGIN_INTERFACE')" class="interface">
        <el-checkbox-group
          v-model="groupInfo.interface"
          @change="recordDataChange('interface', groupInfo.interface)"
        >
          <el-checkbox
            v-for="item in loginInterface"
            :id="'ck' + item"
            :key="item"
            :label="item"
          ></el-checkbox>
        </el-checkbox-group>
      </el-form-item>
      <!-- 当前登录密码 -->
      <el-form-item v-if="!isNoPwd" :error="secondFailedMsg">
        <template #label>
          <span class="login-pwd">{{ $t('COMMON_LOGIN_PASSWORD') }}</span>
        </template>
        <el-input
          v-model="groupInfo.password"
          v-addId.input="'ldapGroupSecondPassword'"
          v-clearable
          type="password"
          autocomplete="new-password"
          clearable
          :maxlength="pwdMaxLen"
          :placeholder="$t('COMMON_PASSWORD_PLACEHOLDER')"
          @input="resetControlValue('password', $event)"
        >
          <template #suffix>
            <ErrorIcon />
            <ClearableIcon />
          </template>
        </el-input>
      </el-form-item>
    </el-form>
  </div>
</template>

<style lang="scss" scoped>
.root-container {
  .login-pwd::before {
    content: '*';
    position: absolute;
    font-size: 12px;
    margin-left: -6px;
    color: var(--o-form-require-color);
    margin-right: 0;
  }

  :deep(.interface) {
    height: 16px;
    .el-form-item__label {
      padding-top: 0;
      padding-bottom: 0;
    }

    .el-form-item__content {
      .el-checkbox {
        height: auto;
      }
    }
  }
}

:deep(.is-required) {
  .el-form-item__label::before {
    content: '*';
    position: absolute;
    font-size: 12px;
    color: var(--o-form-require-color) !important;
    margin-right: 0 !important;
  }
}

:deep(.el-input) {
  width: 320px;
}

:deep(.el-select) {
    width: 320px;
}

:deep(.ldap-form-rule) {
  .el-form-item__label {
    padding-top: 0;
  }
}
</style>

<style lang="scss">
.el-popper.ldap-group-popover {
  max-width: 320px;
  z-index: 2500;
}
</style>
