import { PlusOutlined } from "@ant-design/icons";
import { useEmotionCss } from "@ant-design/use-emotion-css";
import { App, Button, Progress, Tooltip, theme } from "antd";
import { useRef, useState } from "react";
import TextEllipsisMiddle from "../TextEllipsisMiddle";

/** 列表式文件上传 */
const FileUpload: React.FC<{
    /** 添加文件按钮文本 */
    addText?: string;
    /** 上传错误重选文件按钮文本 */
    reselectText?: string;
    /** 上传错误重试按钮文本 */
    retryText?: string;
    /** 选择文件接受限制 */
    accept?: string;
    /** 提示文本 */
    tipText?: string;
    /** 限制大小MB */
    limitSize?: number;
    /** 上传处理回调 */
    onUpload: (file: File, onUploadProgress: (progress: number) => void) => Promise<{ success: boolean; errorType?: 'fileTypeError'; errorMessage?: string; }>;
}> = ({ addText, reselectText, retryText, accept, tipText, limitSize, onUpload }) => {
    const [uploading, setUploading] = useState(false);
    const [file, setFile] = useState<File>();
    const [uploadStatus, setUploadStatus] = useState<'active' | 'exception' | 'success' | 'normal'>('normal');
    const [progress, setProgress] = useState(0);
    const [fileErrorMsg, setFileErrorMsg] = useState<string>();

    const inputRef = useRef<HTMLInputElement>(null);
    const { token } = theme.useToken();
    const { message } = App.useApp();

    const className = useEmotionCss(({ token }) => {
        return {
            width: '100%',
            display: 'flex',
            flexDirection: 'row',
            alignItems: 'center',
            paddingInline: token.paddingXXS,
            borderRadius: token.borderRadiusSM,
            '&.card': {
                paddingBlock: token.paddingXXS,
                borderWidth: 1,
                borderColor: token.colorBorder,
                borderStyle: 'dashed',
            },
            '& input[type="file"]': {
                display: 'none',
            },
            '&:hover': {
                backgroundColor: token.colorBgTextHover,
                '& .delete': {
                    opacity: 1,
                },
            },
            '&.error': {
                borderColor: token.colorError,
            },
            '& .delete': {
                opacity: 0.2,
                marginLeft: token.marginSM,
                color: token.colorTextSecondary,
                '&:hover': {
                    color: token.colorErrorActive,
                },
            },
            '& .loading': {
                // marginLeft: token.marginXXS,
                width: 48,
                height: 40,
                borderRadius: token.borderRadiusXS,
                objectFit: 'cover',
            },
            '& .add': {
                flex: 1,
                display: 'flex',
                flexDirection: 'column',
                alignItems: 'center',
                justifyContent: 'center',
                '& .tip': {
                    marginInline: token.marginXS,
                    color: token.colorWarningText,
                    fontSize: token.fontSize,
                },
            },
            '& .uploading': {
                // paddingLeft: token.paddingXS,
                flex: 1,
                display: 'flex',
                flexDirection: 'column',
                alignItems: 'stretch',
                overflow: 'hidden',
                '& .buttons': {
                    display: 'flex',
                    flexDirection: 'row',
                    alignItems: 'center',
                    justifyContent: 'space-between',
                },
            },
        };
    });

    const handleChoiceFile = () => { inputRef.current?.click(); }
    const handleUpload = async (f: File) => {
        if (limitSize && f.size / 1024 / 1024 > limitSize) {
            const femsg = `文件大小超出限制，最大${limitSize}MB`;
            message.error(femsg);
            setFileErrorMsg(femsg);
            setUploadStatus('exception');
            return;
        }
        try {
            setUploading(true);
            setUploadStatus('active');
            const res = await onUpload?.(f, (p) => setProgress(p));
            if (res.success) {
                setUploadStatus('success');
            }
            else {
                setUploadStatus('exception');
                if (res.errorType === 'fileTypeError') {
                    setFileErrorMsg(res.errorMessage);
                }
            }
        }
        catch {
            setUploadStatus('exception');
        }
        finally {
            setUploading(false);
        }
    }

    return (
        <Tooltip title={uploadStatus === 'exception' ? fileErrorMsg ?? '上传错误' : ''} color={token.colorError}>
            <div className={`${className} card ${uploadStatus === 'exception' ? 'error' : ''}`}>
                <input
                    type="file"
                    ref={inputRef}
                    accept={accept}
                    onChange={async (e) => {
                        const f = e.target.files?.[0];
                        if (!f) {
                            return;
                        }
                        setFile(f);
                        await handleUpload(f);
                    }}
                />
                {!file &&
                    <div className="add">
                        <Button type="link" icon={<PlusOutlined />} disabled={uploading} onClick={handleChoiceFile}>
                            {addText ?? '上传文件'}
                        </Button>
                        {(tipText || limitSize) && <span className="tip">{tipText}{limitSize && `（最大${limitSize}MB）`}</span>}
                    </div>
                }
                {file &&
                    <div className="uploading">
                        <TextEllipsisMiddle suffixCount={3}>{file?.name ?? '未选择文件'}</TextEllipsisMiddle>
                        <Progress style={{ width: uploadStatus === 'active' ? 'calc(100% - 12px)' : '100%' }} percent={progress} size="small" status={uploadStatus} />
                        {uploadStatus === 'exception' &&
                            <div className="buttons">
                                <Button type="link" size="small" onClick={handleChoiceFile}>{reselectText ?? '重新选择文件'}</Button>
                                <Button type="link" size="small" onClick={() => handleUpload(file)}>{retryText ?? '重试'}</Button>
                            </div>
                        }
                    </div>
                }
            </div>
        </Tooltip>
    );
}

export default FileUpload;