import { format, isValid, parse } from 'date-fns';
import { es } from 'date-fns/locale';
import { CalendarIcon, ImagePlus, RotateCcw, Trash2 } from 'lucide-react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useDropzone } from 'react-dropzone';
import { Button } from '@/components/ui/button';
import { Calendar } from '@/components/ui/calendar';
import { Field, FieldLabel } from '@/components/ui/field';
import { Input } from '@/components/ui/input';
import {
    Popover,
    PopoverContent,
    PopoverTrigger,
} from '@/components/ui/popover';
import { Textarea } from '@/components/ui/textarea';
import { MediaPreview } from './MediaPreview';
import { useMediaUpload } from './use-media';

interface ImageMetadata {
    caption: string;
    fuente: string;
    fecha_toma: string;
    hora: string;
    codificacion: string;
}

interface GalleryItem {
    id: string;
    metadata?: ImageMetadata;
    previewUrl?: string;
    mimeType?: string;
}

interface MediaGalleryProps {
    fichaId: number;
    collection: string;
    value: GalleryItem[];
    onChange: (value: GalleryItem[]) => void;
    label?: string;
    minItems?: number;
    hasMetadata?: boolean;
    nativeDateInput?: boolean;
}

const EMPTY_METADATA: ImageMetadata = {
    caption: '',
    fuente: 'UATF',
    fecha_toma: '',
    hora: '',
    codificacion: '',
};

const ACCEPT_TYPES = {
    'image/jpeg': ['.jpg', '.jpeg'],
    'image/png': ['.png'],
    'image/webp': ['.webp'],
} as const;

const ACCEPT_STRING = 'image/jpeg,image/png,image/webp';

function parseDate(value: string): Date | undefined {
    if (!value) {
        return undefined;
    }

    const date = parse(value, 'yyyy-MM-dd', new Date());

    return isValid(date) ? date : undefined;
}

export function MediaGallery({
    fichaId,
    collection,
    value,
    onChange,
    label = 'imágenes',
    minItems = 1,
    hasMetadata = true,
    nativeDateInput = false,
}: MediaGalleryProps) {
    const { upload, status, progress, error } = useMediaUpload(fichaId, collection);
    const valueRef = useRef(value);

    useEffect(() => {
        valueRef.current = value;
    }, [value]);

    const commitChange = useCallback(
        (nextValue: GalleryItem[]) => {
            valueRef.current = nextValue;
            onChange(nextValue);
        },
        [onChange],
    );

    const onDrop = useCallback(
        (acceptedFiles: File[]) => {
            for (const file of acceptedFiles) {
                upload(file, (media) => {
                    commitChange([
                        ...valueRef.current,
                        {
                            id: media.id,
                            ...(hasMetadata ? { metadata: { ...EMPTY_METADATA } } : {}),
                            previewUrl: media.preview_url,
                            mimeType: media.mime_type,
                        },
                    ]);
                });
            }
        },
        [upload, commitChange, hasMetadata],
    );

    const { getRootProps, getInputProps, isDragActive } = useDropzone({
        onDrop,
        accept: ACCEPT_TYPES,
        multiple: true,
    });

    const handleRemove = (index: number) => {
        commitChange(value.filter((_, i) => i !== index));
    };

    const handleReplace = (index: number, file: File) => {
        const currentMetadata = value[index]?.metadata ?? { ...EMPTY_METADATA };
        upload(file, (media) => {
            commitChange(
                value.map((item, i) =>
                    i === index
                        ? {
                                ...item,
                                id: media.id,
                                previewUrl: media.preview_url,
                                mimeType: media.mime_type,
                                ...(hasMetadata ? { metadata: currentMetadata } : {}),
                        }
                        : item,
                ),
            );
        });
    };

    const updateMetadata = (index: number, field: keyof ImageMetadata, fieldValue: string) => {
        commitChange(
            value.map((item, i) =>
                i === index
                    ? {
                            ...item,
                            metadata: {
                                ...(item.metadata ?? EMPTY_METADATA),
                                [field]: fieldValue,
                            },
                    }
                    : item,
            ),
        );
    };

    return (
        <div className="flex flex-col gap-4">
            <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
                {value.map((item, index) => (
                    <GalleryItemCard
                        key={item.id}
                        item={item}
                        index={index}
                        label={label}
                        canRemove={value.length > minItems}
                        uploading={status === 'uploading'}
                        onRemove={() => handleRemove(index)}
                        onReplace={(file) => handleReplace(index, file)}
                        onMetadataChange={(field, val) => updateMetadata(index, field, val)}
                        hasMetadata={hasMetadata}
                        nativeDateInput={nativeDateInput}
                    />
                ))}

                <div
                    {...getRootProps()}
                    className={`flex min-h-56 cursor-pointer flex-col items-center justify-center gap-2 rounded-lg border border-dashed bg-muted/30 p-4 text-center transition-colors ${isDragActive ? 'border-primary/60 bg-primary/5' : ''}`}
                >
                    <input {...getInputProps()} />
                    <ImagePlus className="size-8 text-muted-foreground" />
                    <p className="text-sm text-muted-foreground">
                        {isDragActive ? 'Suelta los archivos aquí' : `Agregar ${label}`}
                    </p>
                    <p className="text-xs text-muted-foreground">JPG, PNG o WebP (máx. 10MB)</p>
                </div>
            </div>

            {status === 'uploading' && (
                <progress value={progress} max="100" className="w-full" />
            )}

            {error && <p className="text-sm text-destructive">{error}</p>}
        </div>
    );
}

interface GalleryItemCardProps {
    item: GalleryItem;
    index: number;
    label: string;
    canRemove: boolean;
    uploading: boolean;
    onRemove: () => void;
    onReplace: (file: File) => void;
    onMetadataChange: (field: keyof ImageMetadata, value: string) => void;
    hasMetadata: boolean;
    nativeDateInput: boolean;
}

function GalleryItemCard({
    item,
    index,
    label,
    canRemove,
    uploading,
    onRemove,
    onReplace,
    onMetadataChange,
    hasMetadata,
    nativeDateInput,
}: GalleryItemCardProps) {
    const fileInputRef = useRef<HTMLInputElement>(null);
    const [dateOpen, setDateOpen] = useState(false);
    const metadata = item.metadata ?? { ...EMPTY_METADATA };
    const selectedDate = parseDate(metadata.fecha_toma);
    const displayDate = selectedDate
        ? format(selectedDate, 'dd/MM/yyyy', { locale: es })
        : 'Fecha';

    const handleReplaceClick = () => {
        fileInputRef.current?.click();
    };

    const handleReplaceFile = (e: React.ChangeEvent<HTMLInputElement>) => {
        const file = e.target.files?.[0];
        if (file) {
            onReplace(file);
        }
        e.target.value = '';
    };

    return (
        <div className="flex flex-col gap-3 rounded-lg border bg-card p-3">
            <div className="group relative aspect-video overflow-hidden rounded-lg border bg-muted/30">
                <MediaPreview
                    src={item.previewUrl ?? ''}
                    mimeType={item.mimeType ?? 'image/jpeg'}
                    alt={`${label} ${index + 1}`}
                />
                <div className="absolute inset-0 flex items-center justify-center bg-black/60 opacity-0 transition-opacity group-hover:opacity-100 [@media(hover:none)]:opacity-100">
                    <div className="flex items-center gap-2">
                        <Button
                            type="button"
                            variant="outline"
                            size="sm"
                            className="bg-black text-white hover:bg-black/80 hover:text-white"
                            onClick={handleReplaceClick}
                            disabled={uploading}
                        >
                            <RotateCcw data-icon="inline-start" />
                            Reemplazar
                        </Button>
                        {canRemove && (
                            <Button
                                type="button"
                                variant="destructive"
                                size="sm"
                                onClick={onRemove}
                                disabled={uploading}
                            >
                                <Trash2 data-icon="inline-start" />
                                Quitar
                            </Button>
                        )}
                    </div>
                </div>
            </div>

            <input
                ref={fileInputRef}
                type="file"
                className="hidden"
                accept={ACCEPT_STRING}
                onChange={handleReplaceFile}
            />

            <div className="flex items-center justify-between">
                <span className="text-sm font-medium">{label} {index + 1}</span>
            </div>

            {hasMetadata && (
                <>
                    <Field>
                        <FieldLabel htmlFor={`caption-${item.id}`} className="text-xs">Descripción</FieldLabel>
                        <Textarea
                            id={`caption-${item.id}`}
                            className="min-h-16 text-xs"
                            value={metadata.caption}
                            onChange={(e) => onMetadataChange('caption', e.target.value)}
                        />
                    </Field>

                    <div className="grid grid-cols-2 gap-3">
                        <Field>
                            <FieldLabel htmlFor={`fuente-${item.id}`} className="text-xs">Fuente</FieldLabel>
                            <Input
                                id={`fuente-${item.id}`}
                                className="h-8 text-xs"
                                readOnly
                                value={metadata.fuente}
                            />
                        </Field>
                        <Field>
                            <FieldLabel htmlFor={`codificacion-${item.id}`} className="text-xs">Codificación</FieldLabel>
                            <Input
                                id={`codificacion-${item.id}`}
                                className="h-8 text-xs"
                                value={metadata.codificacion}
                                onChange={(e) => onMetadataChange('codificacion', e.target.value)}
                            />
                        </Field>
                        <Field>
                            <FieldLabel htmlFor={`fecha-${item.id}`} className="text-xs">Fecha de toma</FieldLabel>
                            {nativeDateInput ? (
                                <Input
                                    id={`fecha-${item.id}`}
                                    type="date"
                                    className="h-8 text-xs"
                                    value={metadata.fecha_toma}
                                    onChange={(e) => onMetadataChange('fecha_toma', e.target.value)}
                                />
                            ) : (
                            <Popover open={dateOpen} onOpenChange={setDateOpen}>
                                <PopoverTrigger asChild>
                                    <Button
                                        id={`fecha-${item.id}`}
                                        type="button"
                                        variant="outline"
                                        size="sm"
                                        data-empty={!selectedDate}
                                        className="h-8 justify-start text-left text-xs font-normal data-[empty=true]:text-muted-foreground"
                                    >
                                        <CalendarIcon data-icon="inline-start" />
                                        {displayDate}
                                    </Button>
                                </PopoverTrigger>
                                <PopoverContent className="w-auto p-0" align="start">
                                    <Calendar
                                        mode="single"
                                        selected={selectedDate}
                                        onSelect={(date) => {
                                            onMetadataChange(
                                                'fecha_toma',
                                                date ? format(date, 'yyyy-MM-dd') : '',
                                            );
                                            setDateOpen(false);
                                        }}
                                        locale={es}
                                        captionLayout="dropdown"
                                    />
                                </PopoverContent>
                            </Popover>
                            )}
                        </Field>
                        <Field>
                            <FieldLabel htmlFor={`hora-${item.id}`} className="text-xs">Hora</FieldLabel>
                            <Input
                                id={`hora-${item.id}`}
                                type="time"
                                step={60}
                                className="h-8 text-xs"
                                value={metadata.hora}
                                onChange={(e) => onMetadataChange('hora', e.target.value)}
                            />
                        </Field>
                    </div>
                </>
            )}
        </div>
    );
}
