import {
  NModal,
  NSpin,
  NUpload,
  NUploadDragger,
  UploadFileInfo,
  useMessage
} from 'naive-ui';
import { defineComponent, watch, PropType, reactive, ref } from 'vue';
import { policy } from '@/components/upload-file/api';
import Copper from '@/components/upload-file/copper';
import axios from 'axios';
import styles from './index.module.less';
import iconUploadAdd from '../../../images/icon-upload-add.png';
import { NaturalTypeEnum, PageEnum } from '@/enums/pageEnum';
import { formatUrlType } from '.';
import { modalClickMask } from '/src/state';

/**
 * 1. 图片上传可以进行裁剪
 * 2. 视频上传可以选择某一帧做为封面
 * 3. 音频只用限制某一种格式
 * 4. 只支持单个上传，因为多个上传没有办法去处理，即有视频，图片等
 */
export default defineComponent({
  name: 'upload-file',
  props: {
    fileList: {
      type: String,
      default: ''
    },
    imageList: {
      type: Array,
      default: () => []
    },
    accept: {
      // 支持类型
      type: String,
      default: '.jpg,.png,.jpeg,.gif'
    },
    showType: {
      type: String as PropType<'default' | 'custom'>,
      default: 'default'
    },
    showFileList: {
      type: Boolean,
      default: true
    },
    max: {
      type: Number as PropType<number>,
      default: 1
    },
    multiple: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    disabled: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    bucketName: {
      type: String,
      default: 'gyt'
    },
    directoryDnd: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    path: {
      type: String,
      default: ''
    },
    fileName: {
      type: String,
      default: ''
    },
    cropper: {
      // 是否裁切， 只有图片才支持 - 失效（不支持）
      type: Boolean as PropType<boolean>,
      default: false
    },
    options: {
      type: Object,
      default: () => {
        return {
          viewMode: 0,
          autoCrop: true, //是否默认生成截图框
          enlarge: 1, //  图片放大倍数
          autoCropWidth: 200, //默认生成截图框宽度
          autoCropHeight: 200, //默认生成截图框高度
          fixedBox: false, //是否固定截图框大小 不允许改变
          previewsCircle: true, //预览图是否是原图形
          title: '上传图片'
        };
      }
    }
  },
  emits: [
    'update:fileList',
    'close',
    'readFileInputEventAsArrayBuffer',
    'remove',
    'finished'
  ],
  setup(props, { emit, expose, slots }) {
    const ossUploadUrl = `https://${props.bucketName}.ks3-cn-beijing.ksyuncs.com/`;
    const message = useMessage();
    const visiable = ref<boolean>(false);
    const btnLoading = ref<boolean>(false);
    const tempFiileBuffer = ref();
    const uploadRef = ref();
    const state = reactive([
      // {
      //   policy: '',
      //   signature: '',
      //   key: '',
      //   KSSAccessKeyId: '',
      //   acl: 'public-read',
      //   name: ''
      // }
    ]) as any;

    const fileListRef = ref<UploadFileInfo[]>([]);
    const initFileList = () => {
      if (props.fileList) {
        const splitName = props.fileList.split('/');
        fileListRef.value = [
          {
            id: new Date().getTime().toString(),
            name: splitName[splitName.length - 1],
            status: 'finished',
            url: props.fileList
          }
        ];
      } else {
        fileListRef.value = [];
      }
    };
    initFileList();
    watch(
      () => props.imageList,
      () => {
        initFileList();
      }
    );
    watch(
      () => props.fileList,
      () => {
        initFileList();
      }
    );
    const handleClearFile = () => {
      uploadRef.value?.clear();
    };
    expose({
      handleClearFile
    });

    const CropperModal = ref();
    const onBeforeUpload = async (options: any) => {
      const file = options.file;
      // 文件大小
      let isLt2M = true;

      const type = file.type.includes('image')
        ? NaturalTypeEnum.IMG
        : file.type.includes('audio')
        ? NaturalTypeEnum.SONG
        : NaturalTypeEnum.VIDEO;

      const size = type === 'IMG' ? 2 : type === 'SONG' ? 20 : 500;
      if (size) {
        isLt2M = file.file.size / 1024 / 1024 < size;
        if (!isLt2M) {
          message.error(`文件大小不能超过${size}M`);
          return false;
        }
      }

      if (!isLt2M) {
        return isLt2M;
      }
      // 是否裁切
      // if (props.cropper && type === 'IMG') {
      //   getBase64(file.file, (imageUrl: any) => {
      //     const target = Object.assign({}, props.options, {
      //       img: imageUrl,
      //       name: file.file.name // 上传文件名
      //     });
      //     visiable.value = true;

      //     setTimeout(() => {
      //       CropperModal.value?.edit(target);
      //     }, 100);
      //   });
      //   return false;
      // }

      try {
        btnLoading.value = true;
        const name = file.file.name;
        const suffix = name.slice(name.lastIndexOf('.'));
        const fileName = `${props.path}${
          props.fileName || Date.now() + suffix
        }`;
        const obj = {
          filename: fileName,
          bucketName: props.bucketName,
          postData: {
            filename: fileName,
            acl: 'public-read',
            key: fileName,
            unknowValueField: []
          }
        };
        const { data } = await policy(obj);

        state.push({
          id: file.id,
          tempFiileBuffer: file.file,
          policy: data.policy,
          signature: data.signature,
          acl: 'public-read',
          key: fileName,
          KSSAccessKeyId: data.kssAccessKeyId,
          name: fileName
        });

        // tempFiileBuffer.value = file.file;
      } catch {
        //
        // message.error('上传失败')
        btnLoading.value = false;
        return false;
      }
      return true;
    };
    const getBase64 = async (img: any, callback: any) => {
      const reader = new FileReader();
      reader.addEventListener('load', () => callback(reader.result));
      reader.readAsDataURL(img);
    };

    const onFinish = (options: any) => {
      console.log(options, 'onFinish');
      onFinishAfter(options);
    };
    const onFinishAfter = async (options: any) => {
      const item = state.find((c: any) => c.id == options.file.id);
      const url = ossUploadUrl + item.key;
      const type = formatUrlType(url);
      let coverImg = '';
      if (type === 'IMG') {
        coverImg = url;
      } else if (type === 'SONG') {
        coverImg = PageEnum.SONG_DEFAULT_COVER;
      } else if (type === 'VIDEO') {
        // 获取视频封面图
        coverImg = await getVideoCoverImg(item.tempFiileBuffer);
      }
      emit('update:fileList', url);
      emit('readFileInputEventAsArrayBuffer', item.tempFiileBuffer);
      console.log(url, 'url onFinishAfter');
      emit('finished', {
        coverImg,
        content: url
      });

      options.file.url = url;
      visiable.value = false;
      btnLoading.value = false;
    };
    const getVideoMsg = (file: any) => {
      return new Promise(resolve => {
        // let dataURL = '';
        const videoElement = document.createElement('video');
        videoElement.currentTime = 1;
        videoElement.src = URL.createObjectURL(file);
        videoElement.addEventListener('loadeddata', function () {
          const canvas: any = document.createElement('canvas'),
            width = videoElement.videoWidth, //canvas的尺寸和图片一样
            height = videoElement.videoHeight;
          canvas.width = width;
          canvas.height = height;
          canvas.getContext('2d').drawImage(videoElement, 0, 0, width, height); //绘制canvas
          // dataURL = canvas.toDataURL('image/jpeg'); //转换为base64
          console.log(canvas);
          canvas.toBlob((blob: any) => {
            // console.log(blob);
            resolve(blob);
          });
        });
      });
    };

    const getVideoCoverImg = async (file: any) => {
      try {
        btnLoading.value = true;
        const imgBlob: any = await getVideoMsg(file || tempFiileBuffer.value);
        const fileName = `${props.path}${Date.now() + '.png'}`;
        const obj = {
          filename: fileName,
          bucketName: props.bucketName,
          postData: {
            filename: fileName,
            acl: 'public-read',
            key: fileName,
            unknowValueField: []
          }
        };
        const { data } = await policy(obj);

        const fileParams = {
          policy: data.policy,
          signature: data.signature,
          key: fileName,
          acl: 'public-read',
          KSSAccessKeyId: data.kssAccessKeyId,
          name: fileName
        } as any;
        const formData = new FormData();
        for (const key in fileParams) {
          formData.append(key, fileParams[key]);
        }

        formData.append('file', imgBlob);
        await axios.post(ossUploadUrl, formData);

        const url = ossUploadUrl + fileName;
        return url;
      } finally {
        btnLoading.value = false;
      }
    };

    const onRemove = async () => {
      emit('update:fileList', '');
      emit('remove');
      btnLoading.value = false;
    };

    // 裁切失败
    // const cropperNo = () => {}
    // 裁切成功
    const cropperOk = async (blob: any) => {
      try {
        const fileName = `${props.path}${
          props.fileName || new Date().getTime() + '.png'
        }`;
        const obj = {
          filename: fileName,
          bucketName: props.bucketName,
          postData: {
            filename: fileName,
            acl: 'public-read',
            key: fileName,
            unknowValueField: []
          }
        };
        const { data } = await policy(obj);

        state.policy = data.policy;
        state.signature = data.signature;
        state.key = fileName;
        state.KSSAccessKeyId = data.kssAccessKeyId;
        state.name = fileName;

        const formData = new FormData();
        for (const key in state) {
          formData.append(key, state[key]);
        }
        formData.append('file', blob);

        await axios.post(ossUploadUrl, formData).then(() => {
          const url = ossUploadUrl + state.key;
          const splitName = url.split('/');
          fileListRef.value = [
            {
              id: new Date().getTime().toString(),
              name: splitName[splitName.length - 1],
              status: 'finished',
              url: url
            }
          ];
          emit('update:fileList', url);
          emit('finished', {
            coverImg: url,
            content: url
          });
          visiable.value = false;
        });
      } catch {
        return false;
      }
    };

    return () => (
      <div class={styles.uploadFile}>
        <NSpin show={btnLoading.value} description="上传中...">
          <NUpload
            ref={uploadRef}
            action={ossUploadUrl}
            data={(file: any) => {
              const item = state.find((c: any) => {
                return c.id == file.file.id;
              });
              const { id, tempFiileBuffer, ...more } = item;
              return { ...more };
            }}
            v-model:fileList={fileListRef.value}
            accept={props.accept}
            multiple={props.multiple}
            max={props.max}
            disabled={props.disabled}
            directoryDnd={props.directoryDnd}
            showFileList={props.showFileList}
            showPreviewButton
            onBeforeUpload={(options: any) => onBeforeUpload(options)}
            onFinish={(options: any) => {
              onFinish(options);
            }}
            onChange={(options: any) => {
              // console.log(options, 'change');
            }}
            onRemove={() => onRemove()}>
            <NUploadDragger>
              {props.showType === 'default' && (
                <div class={styles.uploadBtn}>
                  <img src={iconUploadAdd} class={styles.iconUploadAdd} />
                  <p>上传</p>
                </div>
              )}
              {props.showType === 'custom' && slots.custom && slots.custom()}
            </NUploadDragger>
          </NUpload>
        </NSpin>

        <NModal
          maskClosable={modalClickMask}
          v-model:show={visiable.value}
          preset="dialog"
          showIcon={false}
          class={['modalTitle background']}
          title="上传图片"
          style={{ width: '800px' }}>
          {/* @cropper-no="error" @cropper-ok="success" */}
          <Copper
            ref={CropperModal}
            onClose={() => (visiable.value = false)}
            onCropperOk={cropperOk}
          />
        </NModal>
      </div>
    );
  }
});
