import { defineComponent, onMounted, ref, watch } from 'vue';
import { getGridUploadProps, useNamespace } from '@ibiz-template/vue-util';
import { getCookie } from 'qx-util';
import { RuntimeError } from '@ibiz-template/core';

export const IBizGridFileUpload = defineComponent({
  name: 'IBizGridFileUpload',
  props: getGridUploadProps(),
  setup(props) {
    const ns = useNamespace('grid-file-upload');

    const c = props.controller;

    // 文件列表
    const files = ref<IData[]>([]);

    // 请求头
    const headers = ref<IData>({});

    // 上传文件路径
    const uploadUrl = ref<string>(ibiz.env.baseUrl + ibiz.env.UploadFile);

    // 下载文件路径
    const downloadUrl = ref<string>(ibiz.env.baseUrl + ibiz.env.ExportFile);

    // 模态框是否显示
    const dialogVisible = ref<boolean>(false);

    // 行为是否显示
    const showActions = ref<boolean>(false);

    const onDialogVisibleChange = (value: boolean) => {
      dialogVisible.value = value;
    };

    // 设置files
    const setFiles = (value: string | null | undefined) => {
      if (value === null) {
        files.value = [];
      }
      if (!value) {
        return;
      }
      const _files = JSON.parse(value);
      if (
        value &&
        Object.prototype.toString.call(_files) === '[object Array]'
      ) {
        files.value = _files;
      } else {
        files.value = [];
      }
    };

    // 文件上传缓存对象
    const uploadCache: IData = {
      count: 0,
      cacheFiles: [],
    };

    // 处理参数
    const dataProcess = () => {
      let _url = ibiz.env.baseUrl + ibiz.env.UploadFile;
      if (c.upload_params.length > 0) {
        _url += '?';
        c.upload_params.forEach((item: IData, i: number) => {
          _url += `${Object.keys(item)[0]}=${Object.values(item)[0]}`;
          if (i < c.upload_params.length - 1) {
            _url += '&';
          }
        });
      }
      uploadUrl.value = _url;

      files.value.forEach((file: IData) => {
        let url = `${downloadUrl.value}/${file.id}`;
        if (c.export_params.length > 0) {
          url += '?';
          c.export_params.forEach((item: IData, i: number) => {
            url += `${Object.keys(item)[0]}=${Object.values(item)[0]}`;
            if (i < c.export_params.length - 1) {
              url += '&';
            }
          });
        }
        // eslint-disable-next-line no-param-reassign
        file.url = url;
      });
    };

    // 设置头
    const setHeaders = () => {
      if (getCookie('access_token')) {
        headers.value.Authorization = `Bearer ${getCookie('access_token')}`;
      }
    };
    setHeaders();

    watch(
      () => props.value,
      newVal => {
        setFiles(newVal);
        dataProcess();
      },
      { immediate: true },
    );

    watch(
      () => props.data,
      newVal => {
        c.getParams(newVal);
      },
      { immediate: true, deep: true },
    );

    onMounted(() => {
      c.getParams(props.data);
      setFiles(props.value);
      dataProcess();
    });

    // 上传前回调
    const beforeUpload = () => {
      uploadCache.count += 1;
    };

    // 上传成功回调
    const onSuccess = (response: IData) => {
      if (!response) {
        return;
      }

      // 处理回调数据，并缓存
      const arr: IData[] = [];
      if (response?.length > 0) {
        for (let index = 0; index < response.length; index++) {
          const file = response[index];
          arr.push({ name: file.filename, id: file.fileid });
        }
      } else {
        arr.push({ name: response.filename, id: response.fileid });
      }
      uploadCache.cacheFiles.push(arr);
      uploadCache.count -= 1;

      // 回调都结束后的处理
      if (uploadCache.count === 0) {
        const result: IData[] = [];
        // 添加已有的文件数据
        files.value.forEach((_file: IData) => {
          result.push({ name: _file.name, id: _file.id });
        });

        // 添加缓存的文件数据
        uploadCache.cacheFiles.forEach((item: IData[]) => {
          result.push(...item);
        });

        // 抛出值变更事件
        const value: string | null =
          result.length > 0 ? JSON.stringify(result) : null;
        props.rowDataChange(value);
        // 清空缓存的文件数据
        uploadCache.cacheFiles = [];
      }
    };

    // 上传失败回调
    const onError = (error: IData) => {
      uploadCache.count -= 1;
      throw error;
    };

    // 删除回调
    const onRemove = (file: IData, fileList: IData[]) => {
      const arr: Array<IData> = [];
      fileList.forEach((f: IData) => {
        if (f.id !== file.id) {
          arr.push({ name: f.name, id: f.id });
        }
      });
      const value: string | null = arr.length > 0 ? JSON.stringify(arr) : null;
      props.rowDataChange(value);
    };

    // 计算文件mime类型
    const calcFilemime = (filetype: string) => {
      let mime = 'image/png';
      switch (filetype) {
        case '.wps':
          mime = 'application/kswps';
          break;
        case '.doc':
          mime = 'application/msword';
          break;
        case '.docx':
          mime =
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
          break;
        case '.txt':
          mime = 'text/plain';
          break;
        case '.zip':
          mime = 'application/zip';
          break;
        case '.png':
          mime = 'image/png';
          break;
        case '.gif':
          mime = 'image/gif';
          break;
        case '.jpeg':
          mime = 'image/jpeg';
          break;
        case '.jpg':
          mime = 'image/jpeg';
          break;
        case '.rtf':
          mime = 'application/rtf';
          break;
        case '.avi':
          mime = 'video/x-msvideo';
          break;
        case '.gz':
          mime = 'application/x-gzip';
          break;
        case '.tar':
          mime = 'application/x-tar';
          break;
        default:
          mime = 'image/png';
      }
      return mime;
    };

    /**
     * 下载文件
     */
    const DownloadFile = (url: string, file: IData) => {
      let tempDownloadUrl: string = url;
      const BaseUrl = ibiz.env.baseUrl;
      if (url.startsWith(BaseUrl)) {
        tempDownloadUrl = url.replace(BaseUrl, '');
      }
      // 发送get请求
      ibiz.net
        .get(
          tempDownloadUrl,
          {},
          {},
          {
            responseType: 'blob',
          },
        )
        .then((response: IData) => {
          if (!response || response.status !== 200) {
            throw new RuntimeError('下载文件失败');
          }
          // 请求成功，后台返回的是一个文件流
          if (response.data) {
            // 获取文件名
            const filename = file.name;
            const ext = `.${filename.split('.').pop()}`;
            const filetype = calcFilemime(ext);
            // 用blob对象获取文件流
            const blob = new Blob([response.data], { type: filetype });
            // 通过文件流创建下载链接
            const href = URL.createObjectURL(blob);
            // 创建一个a元素并设置相关属性
            const a = document.createElement('a');
            a.href = href;
            a.download = filename;
            // 添加a元素到当前网页
            document.body.appendChild(a);
            // 触发a元素的点击事件，实现下载
            a.click();
            // 从当前网页移除a元素
            document.body.removeChild(a);
            // 释放blob对象
            URL.revokeObjectURL(href);
          } else {
            throw new RuntimeError('文件流数据不存在');
          }
        });
    };

    // 下载文件
    const onDownload = (file: IData) => {
      const url = `${downloadUrl.value}/${file.id}`;
      DownloadFile(url, file);
    };

    return {
      ns,
      c,
      files,
      headers,
      uploadUrl,
      dialogVisible,
      showActions,
      onDialogVisibleChange,
      beforeUpload,
      onSuccess,
      onError,
      onRemove,
      onDownload,
    };
  },
  render(h) {
    return (
      <div class={this.ns.b()}>
        <i-row>
          {this.files.length > 0 ? (
            <i-col span={12}>
              <i-button
                on-click={() => {
                  this.dialogVisible = true;
                }}
              >
                查看
                <i-badge count={this.files.length}></i-badge>
              </i-button>
            </i-col>
          ) : null}
          <i-col span={this.files.length > 0 ? 12 : 24}>
            {h(
              'IUpload',
              {
                ref: 'fileUploadRowPreview',
                props: {
                  action: this.uploadUrl,
                  headers: this.headers,
                  'default-file-list': this.files,
                  multiple: this.c.multiple,
                  type: this.c.isDrag ? 'drag' : 'select',
                  accept: this.c.accept,
                  'show-upload-list': false,
                  'before-upload': this.beforeUpload,
                  'on-success': this.onSuccess,
                  'on-error': this.onError,
                  'on-remove': this.onRemove,
                  'on-preview': this.onDownload,
                },
              },
              [<i-button icon='ios-cloud-upload-outline'>上传文件</i-button>],
            )}
          </i-col>
        </i-row>

        <i-modal
          class-name={this.ns.b('upload-preview-modal')}
          width='80%'
          footer-hide={true}
          value={this.dialogVisible}
          on-on-visible-change={this.onDialogVisibleChange}
        >
          <ul class={this.ns.be('upload-preview-modal', 'ul')}>
            {this.files.map((file, index) => (
              <li key={index} class={this.ns.be('upload-preview-modal', 'li')}>
                <div class={this.ns.be('upload-preview-modal', 'box')}>
                  <img
                    class={this.ns.be('upload-preview-modal', 'img')}
                    src={file.url}
                  />
                  <div
                    class={this.ns.be('upload-preview-modal', 'actions')}
                    on-mouseenter={() => {
                      this.showActions = true;
                    }}
                    on-mouseleave={() => {
                      this.showActions = false;
                    }}
                  >
                    {this.showActions ? (
                      <span
                        class={this.ns.be('upload-preview-modal', 'download')}
                      >
                        <i-icon
                          type='ios-download-outline'
                          on-click={() => {
                            this.onDownload(file);
                          }}
                        ></i-icon>
                      </span>
                    ) : null}
                    {this.showActions ? (
                      <span
                        class={this.ns.be('upload-preview-modal', 'delete')}
                      >
                        <i-icon
                          type='ios-trash-outline'
                          on-click={() => {
                            this.onRemove(file, this.files);
                          }}
                        ></i-icon>
                      </span>
                    ) : null}
                  </div>
                </div>
                <div class={this.ns.be('upload-preview-modal', 'filename')}>
                  {file.name}
                </div>
              </li>
            ))}
          </ul>
        </i-modal>
      </div>
    );
  },
});
