import React, { ChangeEvent, useCallback, useEffect, useRef } from 'react';
import { Wrapper, HiddenFileInput } from './style';
import useReducer from 'utils/useReducerHelper';
import { genUUID } from 'utils';
import FileListComponent from './sub-components/FileList';
import { uploadFiles } from './sub-components/helpers';
import message from '../message';
import Button from './types/Button';
import Drop from './types/Drop';
import Picture from './types/Picture';
import { IUpload } from './types';

let cancel: any;
export const Upload = function({
    type = 'button',
    label = '上传',
    width = 416,
    multiple = false,
    accept = '*',
    name = 'file',
    disabled,
    onChange,
    defaultFiles = [],
    actionUrl = 'https://www.mocky.io/v2/5cc8019d300000980a055e76',
    propertyPath = '',
    maxUpload = 5,
    additionalData = {},
    ...rest
}: IUpload) {
    const propertyNameList = propertyPath.split('.').filter(Boolean);
    const [state, dispatch] = useReducer({
        files: [],
        isDragOver: false,
    });
    useEffect(() => {
        dispatch({
            files: defaultFiles.map(f => ({
                uid: genUUID(),
                name: f.name,
                data: f.url,
                isLoading: false,
                isError: false,
                progress: 0,
            })),
        });
    }, []);
    const fileInput: any = useRef();
    const onFileInputChange = useCallback(
        ({ target: { files } }: ChangeEvent<HTMLInputElement>) => {
            let filesState = Array.from(files as FileList).map(f => ({
                uid: genUUID(),
                name: f.name,
                file: f,
                data: null,
                isLoading: true,
                isError: false,
                progress: 0,
            }));
            if (filesState.length + state.files.length > maxUpload) {
                message.warning(`上传文件数超过了最大允许上传数：${maxUpload}个`, 4000);
                filesState = filesState.slice(0, maxUpload - state.files.length);
            }
            cancel = uploadFiles(
                filesState,
                actionUrl,
                name,
                dispatch,
                state.files,
                additionalData,
                propertyNameList.join('.'),
                (data: any) => {
                    onChange && onChange(data);
                }
            );
        },
        [state.files, onChange]
    );
    const onRemove = useCallback(
        (index: number, isLoading: boolean) => {
            if (isLoading) {
                cancel[index].cancel('取消上传');
                return;
            }
            (fileInput.current as HTMLInputElement).value = '';
            const files = JSON.parse(JSON.stringify(state.files));
            files.splice(index, 1);
            dispatch({ files });
            onChange && onChange(files);
        },
        [state.files, fileInput]
    );

    let child;
    switch (type) {
        case 'button':
            child = (
                <Button fileInput={fileInput} disabled={disabled} state={state} maxUpload={maxUpload} label={label} />
            );
            break;
        case 'drop':
            multiple = true;
            child = (
                <Drop
                    disabled={disabled}
                    state={state}
                    maxUpload={maxUpload}
                    fileInput={fileInput}
                    dispatch={dispatch}
                    onFileInputChange={onFileInputChange}
                />
            );
            break;
        case 'picture':
            !accept && (accept = 'image/*');
            child = <Picture state={state} onRemove={onRemove} maxUpload={maxUpload} fileInput={fileInput} />;
            break;
    }

    return (
        <Wrapper {...rest}>
            {child}
            {type !== 'picture' && <FileListComponent uploaded={state.files} width={width} onRemove={onRemove} />}
            <HiddenFileInput multiple={multiple} accept={accept} ref={fileInput} onChange={onFileInputChange} />
        </Wrapper>
    );
};

export default Upload;
