import React, { useCallback, useReducer, useImperativeHandle, useMemo } from 'react';
import Button from 'antd/es/button';
import 'antd/es/button/style/index';
import Upload, { UploadProps, RcFile, UploadChangeParam } from 'antd/es/upload';
import 'antd/es/upload/style/index';
import UploadOutlined from '@ant-design/icons/UploadOutlined';
import PlusOutlined from '@ant-design/icons/PlusOutlined';
import { UploadFile } from 'antd/es/upload/interface';
import { loadFile, openFile } from '@jy-fe/utils/es/joyowoUmi';
import {
  XuiUploadButtonProps,
  XuiUploadButtonHandles,
  InitialStateType,
} from './xui-upload-button.d';

const initialState: InitialStateType = {
  fileList: [],
};

const reducer = (
  state: InitialStateType,
  action: {
    type: string;
    payload?: { [key: string]: any };
  },
) => {
  switch (action.type) {
    case 'update':
      return { ...state, ...action.payload };
    default:
      throw new Error();
  }
};

const UploadButton: React.ForwardRefRenderFunction<XuiUploadButtonHandles, XuiUploadButtonProps> = (
  {
    name,
    data,
    apiUrl,
    listType = 'text',
    accept,
    acceptErrorTip,
    maxSize,
    callbackDataKey,
    maxSizeErrorTip,
    nullErrorTip = '请上传文件',
    templateUrl,
    otherJudgment,
    onChange,
  },
  ref,
) => {
  const className = 'xui-ant__upload-button';
  const [state, hookDispatch] = useReducer(reducer, initialState);

  const { fileList } = state;

  const triggerDispatch = useCallback(
    (payload: Partial<InitialStateType>) => {
      hookDispatch({
        type: 'update',
        payload,
      });
    },
    [state],
  );

  const beforeUpload = useCallback(
    (file: RcFile) => {
      if (accept && !accept.includes(file.type)) {
        triggerDispatch({
          fileList: [],
        });
        if (onChange) {
          onChange(new Error(acceptErrorTip));
        }
        return false;
      }
      if (maxSize && file.size > maxSize) {
        triggerDispatch({
          fileList: [],
        });
        if (onChange) {
          onChange(new Error(maxSizeErrorTip));
        }
        return false;
      }
      return true;
    },
    [accept, acceptErrorTip, maxSize, maxSizeErrorTip, onChange],
  );

  const changeUpload = useCallback(
    (info: UploadChangeParam) => {
      if (info.file.status === 'uploading' || info.file.status === 'done') {
        triggerDispatch({
          fileList: [info.file],
        });
        if (info.file.response && onChange) {
          const { status, data: resData, msg } = info.file.response;
          if (!status && resData) {
            onChange(resData[callbackDataKey]);
          } else if (otherJudgment) {
            triggerDispatch({
              fileList: [],
            });
            onChange(otherJudgment(resData || {}));
          } else {
            triggerDispatch({
              fileList: [],
            });
            onChange(new Error(msg));
          }
        }
      }
    },
    [onChange, callbackDataKey],
  );

  const onPreview = useCallback((file: UploadFile<any>) => {
    openFile(file.response.data.url || '');
  }, []);

  const onRemove = useCallback(() => {
    triggerDispatch({
      fileList: [],
    });
    if (onChange) {
      onChange(new Error(nullErrorTip));
    }
  }, [nullErrorTip, onChange]);

  const props: UploadProps = {
    className: `${className}--upload`,
    name,
    listType,
    fileList,
    headers: {
      AuthToken: localStorage.getItem('token') || '',
    },
    action: apiUrl,
    data: data || {},
    beforeUpload,
    onChange: changeUpload,
    onPreview,
    onRemove,
  };

  if (accept) {
    props.accept = accept.join(',');
  }

  useImperativeHandle(ref, () => ({
    clear: () => {
      onRemove();
    },
  }));

  const UploadContent = useMemo(() => {
    if (listType === 'text') {
      return (
        <Button type='default' className={`${className}--btn`}>
          <UploadOutlined />
          上传文件
        </Button>
      );
    }
    if (listType === 'picture-card') {
      if (fileList.length > 0) {
        return null;
      }
      return <PlusOutlined />;
    }
    return null;
  }, [fileList, listType]);

  return (
    <div className={className}>
      <Upload {...props}>{UploadContent}</Upload>
      {templateUrl && (
        <a className={`${className}--templateLoad`} onClick={() => loadFile(templateUrl)}>
          模板下载
        </a>
      )}
    </div>
  );
};

export default React.forwardRef(UploadButton);
