<template>
  <div class="password-box" :class="{ 'block-box': block }">
    <a-popover
      ref="popoverRef"
      :trigger="['focus']"
      :visibleChange="popoverChange"
      destroyTooltipOnHide
      :class="{ 'block-box': block }"
      :visible="isShowIntensity"
    >
      <template #content v-if="isShowIntensity">
        <Intensity v-bind="intensityValue" />
      </template>
      <a-form :model="formValue" :rules="rules" ref="formRef">
        <a-form-item name="password">
          <a-input-password
            :id="`${getId}-1`"
            ref="passwordRef"
            v-model:value="formValue.password"
            @change="passwordChange"
            placeholder="请输入密码"
            :maxlength="maxLength"
            @focus="onFocus"
            @blur="onBlur"
          >
            <template #prefix>
              <LockOutlined style="color: #808695; font-size: 18px" />
            </template>
          </a-input-password>
        </a-form-item>
        <a-form-item name="repeat" v-if="repeat">
          <a-input-password
            :id="`${getId}-2`"
            type="password"
            v-model:value="formValue.repeat"
            placeholder="请再次输入密码"
            :maxlength="maxLength"
            @focus="onFocus"
            @blur="onBlur"
          >
            <template #prefix>
              <LockOutlined style="color: #808695; font-size: 18px" />
            </template>
          </a-input-password>
        </a-form-item>
      </a-form>
    </a-popover>
  </div>
</template>

<script lang="ts" setup>
  import { ref, unref, computed, nextTick, reactive } from 'vue';
  import { LockOutlined } from '@ant-design/icons-vue';
  import Intensity from './components/Intensity.vue';
  import { basicProps } from './props';
  import { bindUUid } from '@/utils';

  const props = defineProps({ ...basicProps });

  defineEmits(['change', 'focus']);

  const isSuccess = ref(false);

  const isShowIntensity = ref(false);

  const getId = bindUUid();

  const formValue = reactive({
    password: props.value,
    repeat: '',
  });

  const password = ref({
    strength: 0,
    tips: null,
    length: false,
    format: false,
    complexity: false,
  });

  const rules = {
    password: [{ required: true, validator: checkPasswordVal, trigger: 'change' }],
    repeat: [{ required: props.repeat, validator: checkRepeat, trigger: 'change' }],
  };

  const popoverRef = ref();
  const passwordRef = ref();

  const intensityValue: any = computed(() => {
    return {
      value: formValue.password,
      complexity: props.complexity,
      minLength: props.minLength,
      maxLength: props.maxLength,
      password: password.value,
      complexityTip: props.complexityTip,
    };
  });

  function onFocus() {
    isShowIntensity.value = true;
  }

  function onBlur() {
    isShowIntensity.value = false;
  }

  function passwordChange() {
    const value: string = formValue.password as string;
    password.value.strength = getStrength(value);
  }

  async function checkPasswordVal(_, value) {
    if (!props.required && !value) {
      isSuccess.value = true;
      return Promise.resolve();
    }
    if (!value) {
      password.value = {
        strength: 0,
        tips: null,
        length: false,
        format: false,
        complexity: false,
      };
      isSuccess.value = false;
      return Promise.reject('请设置密码');
    } else {
      password.value.format = true;
      if (value.length < props.minLength) {
        password.value.length = false;
        password.value.strength = 0;
        password.value.tips = null;
        return Promise.reject(`密码长度至少为${props.minLength}个字符`);
      }
      if (props.complexity) {
        if (checkPassword(value)) {
          password.value.length = true;
          const strength = getStrength(value);
          password.value.strength = strength;
          password.value.tips = props.level[strength];
          if (strength <= 1) {
            password.value.complexity = false;
            return Promise.reject(props.complexityTip);
          } else {
            password.value.complexity = true;
            isSuccess.value = true;
            return Promise.resolve();
          }
        }
      } else {
        password.value.length = true;
        const strength = getStrength(value);
        password.value.strength = strength;
        password.value.tips = props.level[strength];
        password.value.complexity = true;
        isSuccess.value = true;
        return Promise.resolve();
      }
    }
    isSuccess.value = true;
    return Promise.resolve();
  }

  function checkRepeat(_, value) {
    if (!props.required && !value) {
      isSuccess.value = true;
      return Promise.resolve();
    }
    if (!value) {
      return Promise.reject('请再次输入密码');
    } else {
      if (formValue.password !== value) {
        return Promise.reject('两次密码输入不一致');
      }
      return Promise.resolve();
    }
  }

  function checkPassword(password: string): boolean {
    const regExp = /^[A-Za-z0-9~!@#$%^&*()_+=\-.,]{6,32}$/;
    return regExp.test(password);
  }

  function getStrength(password: string): number {
    const reg = {
      lower: /[a-z]/,
      upper: /[A-Z]/,
      number: /[\d]/,
      character: /[~!@#$%^&*()_+=\-.,]/,
    };
    let strength = 0;
    if (reg.lower.test(password)) strength++;
    if (reg.upper.test(password)) strength++;
    if (reg.number.test(password)) strength++;
    if (reg.character.test(password)) strength++;
    return strength;
  }

  function showValidator() {
    passwordRef.value.focus();
    passwordRef.value.blur();
    nextTick(() => {
      passwordRef.value.focus();
    });
  }

  function isValidator() {
    return unref(isSuccess);
  }

  function popoverChange(visible) {
    console.log(visible);
  }

  defineExpose({
    isValidator,
    showValidator,
  });
</script>

<style lang="less" scoped>
  .password-box {
    display: inline-block;
  }

  .block-box {
    display: block;
    width: 100%;
  }
</style>
