<template>
  <component
    is="a-modal"
    v-model:visible="visible"
    :width="tool.getDevice() === 'mobile' ? '100%' : '800px'"
    :title="title"
    :mask-closable="false"
    :ok-loading="loading"
    @cancel="close"
    @before-ok="submit"
  >
    <!-- 表单信息 start -->
    <a-form
      ref="formRef"
      :model="formData"
      :rules="rules"
      :auto-label-width="true"
    >
      <a-row :gutter="16">
        <a-col :span="12">
          <a-form-item field="username" label="账户">
            <a-input v-model="formData.username" placeholder="请输入账户" />
          </a-form-item>
        </a-col>
        <a-col :span="12">
          <a-form-item field="dept_id" label="所属部门">
            <a-tree-select
              v-model="formData.dept_id"
              :data="deptData"
              :field-names="{ key: 'value', title: 'label' }"
              allow-clear
              placeholder="请选择所属部门"
            >
            </a-tree-select>
            <template #extra>
              <div>如果修改了部门，需要重新设置权限</div>
            </template>
          </a-form-item>
        </a-col>
      </a-row>
      <a-row :gutter="16">
        <a-col :span="12">
          <a-form-item field="password" label="密码">
            <a-input-password
              v-model="formData.password"
              :placeholder="
                mode === 'edit' ? '不填写则不修改密码' : '请输入密码'
              "
              @input="checkPasswordSafe"
              @clear="() => (passwordSafePercent = 0)"
              allow-clear
            />
            <template #extra>
              <div v-if="formData.password">
                <a-progress
                  :steps="3"
                  status="success"
                  :percent="passwordSafePercent"
                  animation
                  :show-text="false"
                  size="small"
                />
                <span class="text-xs text-gray-500 ml-1">密码强度</span>
              </div>
            </template>
          </a-form-item>
        </a-col>
        <a-col :span="12">
          <a-form-item field="nickname" label="昵称">
            <a-input v-model="formData.nickname" placeholder="请输入昵称" />
          </a-form-item>
        </a-col>
      </a-row>
      <a-row :gutter="16">
        <a-col :span="12">
          <a-form-item field="role_ids" label="角色">
            <a-tree-select
              v-model="formData.role_ids"
              :data="roleData"
              :field-names="{ key: 'value', title: 'label' }"
              :tree-check-strictly="true"
              allow-clear
              tree-checkable
              placeholder="请选择角色"
            >
            </a-tree-select>
          </a-form-item>
        </a-col>
        <a-col :span="12">
          <a-form-item field="phone" label="手机">
            <a-input v-model="formData.phone" placeholder="请输入手机" />
          </a-form-item>
        </a-col>
      </a-row>
      <a-row :gutter="16">
        <a-col :span="12">
          <a-form-item field="email" label="邮箱">
            <a-input v-model="formData.email" placeholder="请输入邮箱" />
          </a-form-item>
        </a-col>
      </a-row>
      <a-row :gutter="16">
        <a-col :span="24">
          <a-form-item label="状态" field="status">
            <sa-radio
              v-model="formData.status"
              dict="data_status"
              placeholder="请选择状态"
            />
          </a-form-item>
        </a-col>
      </a-row>
      <a-row :gutter="16">
        <a-col :span="24">
          <a-form-item label="备注" field="remark">
            <a-textarea v-model="formData.remark" placeholder="请输入备注" />
          </a-form-item>
        </a-col>
      </a-row>
    </a-form>
    <!-- 表单信息 end -->
  </component>
</template>

<script setup>
import { ref, reactive, computed } from "vue";
import { Message } from "@arco-design/web-vue";
import api from "@/api/system/user";
import tool from "@/utils/tool";
import commonApi from "@/api/common";
import zxcvbn from "zxcvbn";

const emit = defineEmits(["success"]);

// 引用定义
const formRef = ref();
const mode = ref("");
const visible = ref(false);
const loading = ref(false);
const deptData = ref([]);
const roleData = ref([]);
const postData = ref([]);
const passwordSafePercent = ref(0);

let title = computed(() => {
  return "用户管理" + (mode.value == "add" ? "-新增" : "-编辑");
});

// 表单初始值
const initialFormData = {
  id: "",
  avatar: "",
  username: "",
  nickname: "",
  dept_id: "",
  password: "",
  role_ids: [],
  phone: "",
  post_ids: [],
  email: "",
  status: 1,
  remark: "",
};

// 表单信息
const formData = reactive({ ...initialFormData });

// zxcvbn 警告信息中文映射
const warningTranslations = {
  "Straight rows of keys are easy to guess": "键盘上连续的按键容易被猜到",
  "Short keyboard patterns are easy to guess": "简短的键盘模式容易被猜到",
  "Use a longer keyboard pattern with more turns": "使用更长且更复杂的键盘模式",
  'Repeats like "aaa" are easy to guess': '像 "aaa" 这样的重复字符容易被猜到',
  'Repeats like "abcabcabc" are only slightly harder to guess than "abc"':
    '像 "abcabcabc" 这样的重复模式只比 "abc" 稍难猜一点',
  "Sequences like abc or 6543 are easy to guess":
    "像 abc 或 6543 这样的序列容易被猜到",
  "Recent years are easy to guess": "近期的年份容易被猜到",
  "Dates are often easy to guess": "日期通常容易被猜到",
  "This is a top-10 common password": "这是最常用的10个密码之一",
  "This is a top-100 common password": "这是最常用的100个密码之一",
  "This is a very common password": "这是一个非常常见的密码",
  "This is similar to a commonly used password": "这与常用密码相似",
  "A word by itself is easy to guess": "单个单词容易被猜到",
  "Names and surnames by themselves are easy to guess": "单独的姓名容易被猜到",
  "Common names and surnames are easy to guess": "常见的姓名容易被猜到",
};

// zxcvbn 建议信息中文映射
const suggestionTranslations = {
  "Use a few words, avoid common phrases": "使用几个单词，避免常见短语",
  "No need for symbols, digits, or uppercase letters":
    "不需要符号、数字或大写字母",
  "Add another word or two. Uncommon words are better.":
    "添加一两个单词，不常见的单词更好",
  "Capitalization doesn't help very much": "大写字母帮助不大",
  "All-uppercase is almost as easy to guess as all-lowercase":
    "全大写几乎和全小写一样容易猜到",
  "Reversed words aren't much harder to guess": "颠倒的单词不会更难猜",
  "Predictable substitutions like '@' instead of 'a' don't help very much":
    "像用 '@' 代替 'a' 这样的替换帮助不大",
  "Use a longer keyboard pattern with more turns": "使用更长且更复杂的键盘模式",
  "Avoid repeated words and characters": "避免重复的单词和字符",
  "Avoid sequences": "避免使用序列",
  "Avoid recent years": "避免使用近期年份",
  "Avoid years that are associated with you": "避免使用与你相关的年份",
  "Avoid dates and years that are associated with you":
    "避免使用与你相关的日期和年份",
};

// 翻译函数
const translateText = (text, translations) => {
  return translations[text] || text;
};

// 密码强度验证器
const validatePassword = (value, callback) => {
  // 如果是编辑模式且密码为空，则不验证（表示不修改密码）
  if (mode.value === "edit" && !value) {
    callback();
    return;
  }

  // 如果是新增模式，密码必填
  if (mode.value === "add" && !value) {
    callback("密码不能为空");
    return;
  }

  // 如果有值，则进行强度检查
  if (value) {
    // 最小长度检查
    if (value.length < 8) {
      callback("密码长度至少为8位");
      return;
    }

    // 使用 zxcvbn 评估密码强度
    const result = zxcvbn(value);

    // zxcvbn 返回分数 0-4，我们要求至少为 2
    if (result.score < 2) {
      // 翻译反馈信息
      const warningText = result.feedback.warning || "密码过于简单，容易被破解";
      const feedback = translateText(warningText, warningTranslations);

      // 翻译建议信息
      let suggestions = "建议使用字母、数字和特殊字符的组合，避免使用常见密码";
      if (result.feedback.suggestions.length > 0) {
        const translatedSuggestions = result.feedback.suggestions.map((s) =>
          translateText(s, suggestionTranslations)
        );
        suggestions = "建议：" + translatedSuggestions.join("；");
      }

      callback(`${feedback}。${suggestions}`);
      return;
    }
  }

  callback();
};

// 验证规则
const rules = {
  username: [{ required: true, message: "账户不能为空" }],
  dept_id: [{ required: true, message: "部门不能为空" }],
  role_ids: [{ required: true, message: "角色不能为空" }],
  password: [{ validator: validatePassword }],
};

// 打开弹框
const open = async (type = "add", id = "") => {
  mode.value = type;
  // 重置表单数据
  Object.assign(formData, initialFormData);
  passwordSafePercent.value = 0;
  formRef.value.clearValidate();
  visible.value = true;
  await initPage();
  if (type == "edit") {
    const { data } = await api.read(id);
    if (data.postList) {
      const post = data.postList.map((item) => item.id);
      data.post_ids = post;
    }
    const role = data.roleList.map((item) => item.id);
    data.role_ids = role;
    data.password = "";
    setFormData(data);
  }
};

// 初始化页面数据
const initPage = async () => {
  const deptResp = await commonApi.commonGet("/core/dept/accessDept");
  deptData.value = deptResp.data;

  const roleResp = await commonApi.commonGet("/core/role/accessRole");
  roleData.value = roleResp.data;

  const postResp = await commonApi.commonGet("/core/post/accessPost");
  postData.value = postResp.data;
};

// 设置数据
const setFormData = async (data) => {
  for (const key in formData) {
    if (data[key] != null && data[key] != undefined) {
      formData[key] = data[key];
    }
  }
};

// 数据保存
const submit = async (done) => {
  const validate = await formRef.value?.validate();
  if (!validate) {
    loading.value = true;
    let data = { ...formData };
    let result = {};
    if (mode.value === "add") {
      // 添加数据
      data.id = undefined;
      result = await api.save(data);
    } else {
      // 修改数据
      result = await api.update(data.id, data);
    }
    if (result.code === 200) {
      Message.success("操作成功");
      emit("success");
      done(true);
    }
    // 防止连续点击提交
    setTimeout(() => {
      loading.value = false;
    }, 500);
  }
  done(false);
};

// 检查密码安全强度
const checkPasswordSafe = (password) => {
  if (password.length < 1) {
    passwordSafePercent.value = 0;
    return;
  }

  // 使用 zxcvbn 评估密码强度
  const result = zxcvbn(password);

  // 将 zxcvbn 的分数 (0-4) 转换为百分比
  // 0: 0%
  // 1: 0.25 (25%)
  // 2: 0.5 (50%)
  // 3: 0.75 (75%)
  // 4: 1.0 (100%)
  passwordSafePercent.value = result.score * 0.25;
};

// 关闭弹窗
const close = () => {
  visible.value = false;
  passwordSafePercent.value = 0;
};

defineExpose({ open, setFormData });
</script>
