'use client';

import React, { useState } from 'react';
import { Button, List, Progress, Upload } from 'antd';
import { message } from '@/lib/feedback/message';
import { File, FileText, Image, Trash2, Upload as UploadIcon } from 'lucide-react';
import { iconTokenSize, ICON_SIZE_MD } from '@/components/icons';
import type { UploadFile, UploadProps } from 'antd';
import type { UploadRequestOption } from 'rc-upload/lib/interface';
import apiClient from '@/lib/api/client';
import styles from './FileUpload.module.scss';

const { Dragger } = Upload;

interface FileUploadProps {
    endpoint?: string;
    accept?: string;
    maxSize?: number; // em MB
    maxCount?: number;
    multiple?: boolean;
    onUploadSuccess?: (file: unknown) => void;
    onUploadError?: (error: unknown) => void;
    onRemove?: (file: UploadFile) => void;
    value?: UploadFile[];
    onChange?: (fileList: UploadFile[]) => void;
    listType?: 'text' | 'picture' | 'picture-card';
    showUploadList?: boolean;
}

export function FileUpload({
    endpoint = '/api/upload',
    accept = '*',
    maxSize = 10,
    maxCount = 5,
    multiple = true,
    onUploadSuccess,
    onUploadError,
    onRemove,
    value,
    onChange,
    listType = 'text',
    showUploadList = true,
}: FileUploadProps) {
    const [fileList, setFileList] = useState<UploadFile[]>(value || []);
    const [uploading, setUploading] = useState(false);

    const handleChange: UploadProps['onChange'] = (info) => {
        let newFileList = [...info.fileList];

        // Limitar número de arquivos
        if (newFileList.length > maxCount) {
            newFileList = newFileList.slice(0, maxCount);
            message.warning(`Máximo de ${maxCount} arquivos permitidos`);
        }

        // Atualizar fileList
        newFileList = newFileList.map((file) => {
            if (file.response) {
                file.url = file.response.url;
            }
            return file;
        });

        setFileList(newFileList);
        onChange?.(newFileList);
    };

    const beforeUpload = (file: File) => {
        const sizeMb = file.size / 1024 / 1024;
        if (sizeMb > maxSize) {
            message.error(`Tamanho máximo por arquivo: ${maxSize} MB.`);
            return Upload.LIST_IGNORE;
        }
        if (accept && accept !== '*') {
            const type = (file.type || '').toLowerCase();
            const name = (file.name || '').toLowerCase();
            const allowed = accept.split(',').map((s) => s.trim().toLowerCase());
            const matches = allowed.some((a) => {
                if (a.startsWith('.')) return name.endsWith(a);
                if (a.endsWith('/*')) return type.startsWith(a.slice(0, -1));
                return type === a || type.startsWith(a + '/');
            });
            if (!matches) {
                message.error(`Formato não aceito. Formatos aceitos: ${accept}`);
                return Upload.LIST_IGNORE;
            }
        }
        return true;
    };

    const customRequest = async (options: UploadRequestOption) => {
        const { onSuccess, onError, file, onProgress } = options;
        const fileObj = file as File;

        const formData = new FormData();
        formData.append('file', fileObj);

        try {
            setUploading(true);
            const response = await apiClient.post(endpoint, formData, {
                headers: {
                    'Content-Type': 'multipart/form-data',
                },
                onUploadProgress: (progressEvent) => {
                    if (progressEvent.total) {
                        const percent = Math.round(
                            (progressEvent.loaded * 100) / progressEvent.total
                        );
                        onProgress?.({ percent });
                    }
                },
            });

            onSuccess?.(response.data, fileObj);
            onUploadSuccess?.(response.data);
            message.success(`${fileObj.name} enviado com sucesso!`);
        } catch (err: unknown) {
            const error = err as { response?: { data?: { message?: string } } };
            const uploadError = err as { response?: { data?: { message?: string } } };
            onError?.(uploadError as Error | ProgressEvent<EventTarget>);
            onUploadError?.(err);
            message.error(
                `Erro ao enviar ${fileObj.name}: ${error.response?.data?.message || 'Erro desconhecido'}`
            );
        } finally {
            setUploading(false);
        }
    };

    const handleRemove = (file: UploadFile) => {
        const newFileList = fileList.filter((item) => item.uid !== file.uid);
        setFileList(newFileList);
        onChange?.(newFileList);
        onRemove?.(file);
    };

    const getFileIcon = (file: UploadFile) => {
        const type = file.type || '';
        if (type.startsWith('image/')) {
            return <Image size={iconTokenSize.xl} style={{ color: '#1890ff' }} aria-hidden />;
        }
        if (type === 'application/pdf') {
            return <FileText size={iconTokenSize.xl} style={{ color: '#ff4d4f' }} aria-hidden />;
        }
        return <File size={iconTokenSize.xl} aria-hidden />;
    };

    const uploadProps: UploadProps = {
        fileList,
        onChange: handleChange,
        beforeUpload,
        customRequest,
        accept,
        multiple,
        onRemove: handleRemove,
        listType,
        showUploadList,
    };

    if (listType === 'picture-card') {
        return (
            <Upload {...uploadProps}>
                {fileList.length < maxCount && (
                    <div>
                        <UploadIcon size={ICON_SIZE_MD} aria-hidden />
                        <div style={{ marginTop: 8 }}>Upload</div>
                    </div>
                )}
            </Upload>
        );
    }

    return (
        <div>
            <Dragger
                {...uploadProps}
                disabled={uploading || fileList.length >= maxCount}
                className={styles.uploadDropzone}
            >
                <p className={styles.uploadLeadText}>Choose a file with a size up to {maxSize}MB.</p>
                <div className={styles.uploadCtaButton}>
                    <UploadIcon size={ICON_SIZE_MD} aria-hidden />
                    <span>Drag & Drop to Upload</span>
                </div>
                <p className={styles.uploadOrText}>or</p>
                <p className={styles.uploadBrowseText}>Browse</p>
                {accept && accept !== '*' ? (
                    <p className={styles.uploadHintText}>Formatos aceitos: {accept}</p>
                ) : null}
            </Dragger>

            {fileList.length > 0 && (
                <List
                    style={{ marginTop: 16 }}
                    dataSource={fileList}
                    renderItem={(file) => (
                        <List.Item
                            actions={[
                                <Button
                                    key="remove"
                                    type="text"
                                    danger
                                    icon={<Trash2 size={ICON_SIZE_MD} aria-hidden />}
                                    onClick={() => handleRemove(file)}
                                    disabled={uploading}
                                >
                                    Remover
                                </Button>,
                            ]}
                        >
                            <List.Item.Meta
                                avatar={getFileIcon(file)}
                                title={file.name}
                                description={
                                    file.status === 'uploading' ? (
                                        <Progress percent={file.percent} size="small" />
                                    ) : (
                                        `${(file.size! / 1024 / 1024).toFixed(2)} MB`
                                    )
                                }
                            />
                        </List.Item>
                    )}
                />
            )}
        </div>
    );
}
