<!--
 * @since: 2024-12-30
 * BasicInfo.vue
-->
<template>
  <CardLayout title="基础配置" :isShowWraning="false" :mandatory="false">
    <el-form
      ref="ruleFormRef"
      label-width="auto"
      :model="ruleForm"
      :rules="formRules"
      :label-position="labelPosition"
      class="el-form-outer"
    >
      <el-form-item label="消息样式: " prop="messageType">
        <el-radio-group v-model="ruleForm.messageType" :disabled="!pageScopedDisabled">
          <el-radio :value="item.value" v-for="item in messageTypeOptions" :key="item.value"
            >{{ item.label }}
          </el-radio>
        </el-radio-group>
      </el-form-item>
      <el-form-item label="消息标题: " prop="title">
        <el-input
          v-model="ruleForm.title"
          placeholder="请输入20字以内的消息标题"
          maxlength="20"
          show-word-limit
          :disabled="!pageScopedDisabled"
        />
      </el-form-item>
      <el-form-item label="Banner图片: " prop="bannerUrl" v-if="ruleForm.messageType === MessageTypeEnum.BANNER">
        <el-upload
          ref="upload"
          v-model:file-list="fileList"
          :action="actionUrl"
          :headers="getHeaders()"
          :data="{ bizType: 'PUSH_MESSAGE' }"
          :on-success="handleAvatarSuccess"
          :before-upload="beforeAvatarUpload"
          :limit="1"
          list-type="picture-card"
          :on-exceed="handleExceed"
          :on-preview="handlePictureCardPreview"
          :disabled="!pageScopedDisabled"
        >
          <el-icon class="avatar-uploader-icon"><Plus /></el-icon>
        </el-upload>
        <span class="tip-message">支持格式：.jpg、.jpeg、.png，文件不超过 20MB，建议上传 4:3 比例的图片！</span>
      </el-form-item>

      <el-form-item label="推送渠道: " prop="pushChannel">
        <el-checkbox-group v-model="ruleForm.pushChannel">
          <el-checkbox
            v-for="item in pushChannelName"
            :key="item.value"
            :value="item.value"
            :label="item.label"
            :disabled="!pageScopedDisabled"
          />
        </el-checkbox-group>
      </el-form-item>
      <el-form-item label="失效时间: " prop="expirationTime">
        <el-date-picker
          v-model="ruleForm.expirationTime"
          type="datetime"
          placeholder="请选择失效时间"
          format="YYYY/MM/DD hh:mm:ss"
          value-format="YYYY-MM-DD hh:mm:ss"
          :disabled="!pageScopedDisabled"
          :disabled-date="disabledDate"
        />
        <span class="tip-message">请注意：超过该日期后，【APP/PC 主页】将不再弹出消息！</span>
      </el-form-item>
      <PushObject
        ref="childFromRef"
        :recipientType="ruleForm.recipientType"
        :userGroupList="ruleForm.userGroupList"
        :customUserList="ruleForm.customUserList"
        :disabled="!pageScopedDisabled"
        :has-all="true"
      />
    </el-form>
  </CardLayout>
  <el-dialog v-model="dialogVisible">
    <img w-full :src="dialogImageUrl" alt="Preview Image" />
  </el-dialog>
</template>

<script setup lang="ts">
  import { ref, watch, computed, unref } from 'vue';
  import { useRoute } from 'vue-router';
  import type {
    FormInstance,
    FormProps,
    FormRules,
    UploadProps,
    UploadUserFile,
    UploadInstance,
    UploadRawFile,
  } from 'element-plus';
  import { ElMessage, genFileId } from 'element-plus';
  import { Plus } from '@element-plus/icons-vue';
  import PushObject from '../../components/PushObject.vue';
  import CardLayout from './CardLayout.vue';
  import { RuleFormView, MessageTypeEnum, RuleFormAdd } from '../type';
  import { messageTypeOptions, pushChannelName } from '../../constant';
  import urlJoin from 'url-join';
  import { useGlobSetting } from '@/hooks/setting';
  import { getHeaders } from '@/utils/http/axios';
  import { isEmpty } from 'lodash-es';

  const { urlPrefix } = useGlobSetting();
  interface Props {
    dataSoure: RuleFormView;
    isDisabled: boolean;
  }
  const props = defineProps<Props>();
  const route = useRoute();
  const pageScopedDisabled = computed(() => props.isDisabled === false || route.query.viewModel === 'edit');
  const labelPosition = ref<FormProps['labelPosition']>('left');
  const childFromRef = ref<InstanceType<typeof PushObject>>();
  const actionUrl = computed(() => {
    return urlJoin(urlPrefix!, `/admin/minio/uploadFile`);
  });

  /**
   * 表单相关操作
   */
  type Rule = Omit<RuleFormView, 'introduction' | 'contentType' | 'content' | 'contentUrl' | 'operator'>;
  const formRules: FormRules<Rule> = {
    messageType: [{ required: true, trigger: 'change', message: '请选择消息样式' }],
    title: [{ required: true, trigger: 'change', message: '请输入消息标题' }],
    pushChannel: [{ required: true, trigger: 'change', message: '请选择推送渠道' }],
    recipientType: [{ required: true, trigger: 'change', message: '请选择推送对象' }],
    bannerUrl: [{ required: true, trigger: 'change', message: '请选择banner图片' }],
  };
  const ruleForm = ref<Rule>({
    messageType: MessageTypeEnum.TEXT,
    title: '',
    bannerUrl: '',
    pushChannel: [],
    expirationTime: '',
    recipientType: 1, // 默认全员
    userGroupList: [],
    customUserList: [],
  });
  const fileList = ref<UploadUserFile[]>([]);

  watch(
    () => props.dataSoure,
    (value) => {
      if (value) {
        ruleForm.value = { ...value };
        if (!isEmpty(value.bannerUrl)) {
          fileList.value = [
            {
              name: '',
              url: value.bannerUrl,
            },
          ];
        }
      }
    },
    {
      immediate: true,
      deep: true,
    },
  );

  const ruleFormRef = ref<FormInstance>();
  const isValidate = ref<boolean>();
  const validate = async () => {
    if (!ruleFormRef.value) return;
    try {
      const isSuccess = await ruleFormRef.value.validate();
      return isSuccess;
    } catch (error) {
      ElMessage.error('请完善信息填写');
      throw error;
    }
  };

  const handleAvatarSuccess: UploadProps['onSuccess'] = (response) => {
    // 注意，这里 response 是 没有被拦截处理
    ruleForm.value.bannerUrl = response.data.url;
  };

  // 上传前限制
  const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
    if (!['image/jpeg', 'image/png', 'image/jpg'].includes(rawFile.type)) {
      ElMessage.error('文件格式仅支持：.jpg, .jpeg, .png');
      return false;
    } else if (rawFile.size / 1024 / 1024 > 20) {
      ElMessage.error('文件不支持超过 20MB!');
      return false;
    }
    return true;
  };

  // 图片预览
  const dialogImageUrl = ref('');
  const dialogVisible = ref(false);
  const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
    dialogImageUrl.value = uploadFile.url!;
    dialogVisible.value = true;
  };

  const upload = ref<UploadInstance>();
  const handleExceed: UploadProps['onExceed'] = (files) => {
    upload.value!.clearFiles();
    const file = files[0] as UploadRawFile;
    file.uid = genFileId();
    upload.value!.handleStart(file);
  };

  const buildFromData = () => {
    const childValue = childFromRef.value!.getChildValue();
    childFromRef.value!.submitForm().then((res) => {
      isValidate.value = res;
    });

    const basicInfo = { ...unref(ruleForm) } as RuleFormAdd;
    if (childValue) {
      basicInfo.recipientType = childValue.recipientType!;
      basicInfo.userGroupList = childValue.userGroupList!;
      basicInfo.customUserList = childValue.customUserList!;
    }
    return basicInfo;
  };

  const disabledDate = (time: Date) => {
    return time.getTime() < Date.now();
  };

  defineExpose({ validate, buildFromData });
</script>

<style scoped lang="scss">
  .avatar-uploader .avatar {
    width: 58px;
    height: 58px;
    display: block;
  }
  .avatar-uploader .el-upload {
    border: 1px dashed var(--el-border-color);
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: var(--el-transition-duration-fast);
  }

  .avatar-uploader .el-upload:hover {
    border-color: var(--el-color-primary);
  }

  .el-icon.avatar-uploader-icon {
    font-size: 28px;
    color: #8c939d;
    width: 58px;
    height: 58px;
    text-align: center;
  }

  .tip-message {
    margin-left: 20px;
  }
</style>
