<template>
  <el-input v-model="model.verifyCode" :disabled="props.disabled" placeholder="请输入验证码">
    <template #prepend>
      <el-icon>
        <icon-cs-validate />
      </el-icon>
    </template>
    <template #append>
      <el-button v-if="model.verifyImage === 'none'" @click="updateVerifyImage">
        获取验证码
      </el-button>
      <el-icon v-else-if="model.verifyImage === 'fetching'" class="is-loading">
        <icon-ep-loading />
      </el-icon>
      <template v-else>
        <el-popover :content="popOverMessage" popper-style="text-align: center">
          <template #reference>
            <img
              :src="model.verifyImage.img"
              alt="验证码"
              class="verify-image"
              draggable="false"
              @click="updateVerifyImage"
            />
          </template>
        </el-popover>
      </template>
    </template>
  </el-input>
</template>
<style lang="scss" scoped>
.verify-image {
  height: 30px;
  user-select: none;
}
</style>
<script lang="ts" setup>
import { request } from '@/api';
import { verifyRespSchema } from '@/schemas/response';
import { timeout } from '@/utils';
import { computed, ref, watch } from 'vue';

export type VerifyImagePath =
  | 'none'
  | 'fetching'
  | {
      key: string;
      img: string;
    };
const model = defineModel<{
  verifyImage: VerifyImagePath;
  verifyCode: string;
}>({ required: true });
const coolDownDuration = 5;
const props = defineProps<{ disabled: boolean }>();
const canRefresh = computed(() => refreshCoolDown.value === 0);
const popOverMessage = ref('');
const refreshCoolDown = ref(0);
watch(
  () => refreshCoolDown.value,
  (value) => {
    if (value > 0) {
      popOverMessage.value = `过${refreshCoolDown.value.toFixed(0)}秒再换吧`;
    } else {
      popOverMessage.value = '看不清? 点击换一张';
    }
  },
);
watch(
  () => model.value.verifyImage,
  (value) => {
    if (value === 'none') {
      refreshCoolDown.value = 0;
    }
  },
);

async function cooldown() {
  for (refreshCoolDown.value = coolDownDuration; refreshCoolDown.value > 0; ) {
    refreshCoolDown.value--;
    await timeout(1000);
  }
}

async function updateVerifyImage() {
  if (model.value.verifyImage === 'fetching' || !canRefresh.value) {
    return;
  }
  let succeed = false;
  const original = model.value.verifyImage;
  model.value.verifyImage = 'fetching';
  try {
    const verifyResponse = await request(verifyRespSchema, {
      url: '/api/user/verify',
      errorDescription: '获取验证码失败',
    });
    if (!verifyResponse) return;
    const { img, key } = verifyResponse.data;
    model.value.verifyImage = {
      key: key,
      img,
    };
    cooldown().then();
    succeed = true;
  } finally {
    if (!succeed) {
      model.value.verifyImage = original;
    }
  }
}
</script>
