import { FileImage, Upload, X } from 'lucide-react';
import { useEffect, useRef, useState, useId } from 'react';
import {
    Attachment,
    AttachmentAction,
    AttachmentActions,
    AttachmentContent,
    AttachmentDescription,
    AttachmentMedia,
    AttachmentTitle,
    AttachmentTrigger,
} from '@/components/ui/attachment';
import { uploadFile, UploadError } from '@/lib/upload';

type FileUploadProps = {
    value: string | null;
    onChange: (key: string | null) => void;
    folder?: string;
    accept?: string;
    onUploadingChange?: (uploading: boolean) => void;
    existingUrl?: string | null;
    onFileMeta?: (meta: { size: number; type: string } | null) => void;
};

function formatFileSize(bytes: number): string {
    if (bytes < 1024) {
        return `${bytes} B`;
    }

    if (bytes < 1024 * 1024) {
        return `${(bytes / 1024).toFixed(1)} KB`;
    }

    return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

export function FileUpload({ value, onChange, folder, accept = 'image/jpeg,image/png,image/webp,image/gif', onUploadingChange, existingUrl, onFileMeta }: FileUploadProps) {
    const inputRef = useRef<HTMLInputElement>(null);
    const uploadId = useId();
    const [uploading, setUploading] = useState(false);
    const [error, setError] = useState<string | null>(null);
    const [fileName, setFileName] = useState<string | null>(null);
    const [fileSize, setFileSize] = useState<number | null>(null);
    const [preview, setPreview] = useState<string | null>(null);

    useEffect(() => {
        onUploadingChange?.(uploading);
    }, [uploading, onUploadingChange]);

    async function handleFileChange(e: React.ChangeEvent<HTMLInputElement>) {
        const file = e.target.files?.[0];

        if (!file) {
            return;
        }

        setError(null);
        setUploading(true);
        setFileName(file.name);
        setFileSize(file.size);

        const objectUrl = URL.createObjectURL(file);
        setPreview(objectUrl);

        try {
            const key = await uploadFile(file, folder);
            onChange(key);
            onFileMeta?.({ size: file.size, type: file.type });
        } catch (err) {
            const message = err instanceof UploadError ? err.message : 'Gagal mengunggah file.';
            setError(message);
            setPreview(null);
            setFileName(null);
            setFileSize(null);
            onFileMeta?.(null);

        } finally {
            setUploading(false);

            if (inputRef.current) {
                inputRef.current.value = '';
            }
        }
    }

    function handleRemove(e: React.MouseEvent) {
        e.stopPropagation();
        onChange(null);
        setFileName(null);
        setFileSize(null);
        setPreview(null);
        setError(null);
        onFileMeta?.(null);

        if (inputRef.current) {
            inputRef.current.value = '';
        }
    }

    const state = uploading ? 'uploading' : error ? 'error' : value ? 'done' : 'idle';

    return (
        <>
            <input
                ref={inputRef}
                type="file"
                accept={accept}
                onChange={handleFileChange}
                className="hidden"
                id={uploadId}
            />

            <Attachment state={state} orientation="horizontal" className='w-full'>
                <AttachmentTrigger
                    onClick={() => inputRef.current?.click()}
                    aria-label={value ? 'Ganti file' : 'Pilih file untuk diunggah'}
                />

                <AttachmentMedia variant={preview || existingUrl ? 'image' : 'icon'}>
                    {preview ? (
                        <img src={preview} alt={fileName ?? 'Preview'} />
                    ) : existingUrl && value ? (
                        <img src={existingUrl} alt="Bukti" />
                    ) : uploading ? (
                        <Upload className="animate-pulse" />
                    ) : (
                        <FileImage />
                    )}
                </AttachmentMedia>

                <AttachmentContent>
                    {value ? (
                        <>
                            <AttachmentTitle>{fileName}</AttachmentTitle>
                            <AttachmentDescription>
                                {fileSize ? formatFileSize(fileSize) : 'Terupload'}
                            </AttachmentDescription>
                        </>
                    ) : uploading ? (
                        <>
                            <AttachmentTitle>Mengunggah...</AttachmentTitle>
                            <AttachmentDescription>Memproses file</AttachmentDescription>
                        </>
                    ) : error ? (
                        <>
                            <AttachmentTitle>Gagal</AttachmentTitle>
                            <AttachmentDescription>{error}</AttachmentDescription>
                        </>
                    ) : (
                        <>
                            <AttachmentTitle>Unggah File</AttachmentTitle>
                            <AttachmentDescription>Opsional · JPG, PNG, WebP, GIF · Maks 10MB</AttachmentDescription>
                        </>
                    )}
                </AttachmentContent>

                {value && (
                    <AttachmentActions>
                        <AttachmentAction aria-label="Hapus file" onClick={handleRemove}>
                            <X />
                        </AttachmentAction>
                    </AttachmentActions>
                )}
            </Attachment>
        </>
    );
}
