import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from '@/components/ui/select';
import {
    Sheet,
    SheetContent,
    SheetDescription,
    SheetFooter,
    SheetHeader,
    SheetTitle,
} from '@/components/ui/sheet';
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import { Loader2 } from 'lucide-react';
import { useEffect, useState } from 'react';
import { MapContainer, Marker, TileLayer, useMap } from 'react-leaflet';

const markerIcon = new L.Icon({
    iconUrl: 'https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png',
    iconSize: [25, 41],
    iconAnchor: [12, 41],
});

export interface Field {
    key: string;
    name: string;
    label: string;
    type: 'text' | 'number' | 'email' | 'select' | 'file' | 'password' | 'map';
    required?: boolean;
    placeholder?: string;
    options?: { value: string; label: string }[];
    accept?: string;
    baseURL?: string;
    autoComplete?: string;
    numericOnly?: boolean;
    numericNoFormat?: boolean;
    min?: number;
    max?: number;
    minLength?: number;
    maxLength?: number;
}

interface CustomFormSheetProps<T> {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    data?: T;
    onSave: (data: T) => void;
    fields: Field[];
    title: string;
}

// Komponen bantu untuk set posisi map dari state
const SetViewOnChange = ({ coords }: { coords: [number, number] }) => {
    const map = useMap();
    useEffect(() => {
        map.setView(coords, map.getZoom());
    }, [coords]);
    return null;
};

export default function CustomFormSheet<T extends Record<string, any>>({
    open,
    onOpenChange,
    data,
    onSave,
    fields,
    title,
}: CustomFormSheetProps<T>) {
    const [formData, setFormData] = useState<T>({} as T);
    const [processing, setProcessing] = useState(false);
    const [previews, setPreviews] = useState<Record<string, string | null>>({});
    const [defaultCoords, setDefaultCoords] = useState<[number, number]>([
        -1.49, 120.82,
    ]);

    const isEdit = Boolean(data);

    useEffect(() => {
        setFormData(data || ({} as T));

        // Ambil lokasi saat ini
        if (!isEdit && navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(
                (pos) => {
                    const { latitude, longitude } = pos.coords;
                    setDefaultCoords([latitude, longitude]);
                    setFormData((prev) => ({
                        ...(prev as any),
                        latitude: latitude.toFixed(6),
                        longitude: longitude.toFixed(6),
                    }));
                },
                () => {
                    console.warn('Gagal mendapatkan lokasi, pakai default.');
                },
            );
        }

        // Inisialisasi preview file jika ada
        const initialPreviews: Record<string, string | null> = {};
        fields.forEach((field) => {
            if (field.type === 'file' && data?.[field.key]) {
                initialPreviews[field.key] = field.baseURL
                    ? `${field.baseURL}/${data[field.key]}`
                    : String(data[field.key]);
            } else {
                initialPreviews[field.key] = null;
            }
        });
        setPreviews(initialPreviews);
    }, [data, open, fields]);

    const handleSelectChange = (key: string, value: string | number) => {
        setFormData((prev) => ({ ...(prev as any), [key]: value }));
    };

    const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        if (e.target.files?.length) {
            const file = e.target.files[0];
            const name = e.target.name;
            setFormData((prev) => ({ ...(prev as any), [name]: file }));
            setPreviews({ ...previews, [name]: URL.createObjectURL(file) });
        }
    };

    const handleSubmit = (e: React.FormEvent) => {
        e.preventDefault();
        const dataToSave: any = { ...formData };
        onSave(dataToSave as T);
        onOpenChange(false);
    };

    return (
        <Sheet open={open} onOpenChange={onOpenChange}>
            <SheetContent
                className="h-full overflow-y-auto"
                onInteractOutside={(e) => e.preventDefault()}
            >
                <SheetHeader>
                    <SheetTitle>
                        {title}
                        <SheetDescription className="text-mute text-xs font-thin">
                            Periksa data sebelum disimpan
                        </SheetDescription>
                    </SheetTitle>
                </SheetHeader>

                <form id="custom-form" onSubmit={handleSubmit}>
                    {fields.map((field) => (
                        <div key={field.key} className="mb-4 px-4">
                            <Label htmlFor={field.key} className="mb-2 block">
                                {field.label}
                            </Label>

                            {field.type === 'select' ? (
                                <Select
                                    value={
                                        formData[field.key] !== undefined
                                            ? String(formData[field.key])
                                            : ''
                                    }
                                    onValueChange={(v) => {
                                        const val = Number(v) || v;
                                        handleSelectChange(field.key, val);
                                    }}
                                >
                                    <SelectTrigger
                                        id={field.key}
                                        name={field.name}
                                    >
                                        <SelectValue placeholder="-- Pilih --" />
                                    </SelectTrigger>
                                    <SelectContent>
                                        {field.options?.map((opt) => (
                                            <SelectItem
                                                key={opt.value}
                                                value={String(opt.value)}
                                            >
                                                {opt.label}
                                            </SelectItem>
                                        ))}
                                    </SelectContent>
                                </Select>
                            ) : field.type === 'file' ? (
                                <div>
                                    {previews[field.key] && (
                                        <img
                                            src={previews[field.key]!}
                                            alt="Preview"
                                            className="mt-2 mb-2 h-24 w-24 rounded-md object-cover"
                                        />
                                    )}
                                    <Input
                                        id={field.key}
                                        name={field.name}
                                        type="file"
                                        onChange={handleFileChange}
                                        accept={field.accept}
                                        required={field.required}
                                    />
                                </div>
                            ) : field.type === 'map' ? (
                                <div className="h-[300px] overflow-hidden rounded-lg border">
                                    <MapContainer
                                        center={[
                                            Number(formData.latitude) ||
                                                defaultCoords[0],
                                            Number(formData.longitude) ||
                                                defaultCoords[1],
                                        ]}
                                        zoom={15}
                                        style={{
                                            height: '100%',
                                            width: '100%',
                                        }}
                                    >
                                        <TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
                                        <Marker
                                            draggable
                                            position={[
                                                Number(formData.latitude) ||
                                                    defaultCoords[0],
                                                Number(formData.longitude) ||
                                                    defaultCoords[1],
                                            ]}
                                            icon={markerIcon}
                                            eventHandlers={{
                                                dragend: (e) => {
                                                    const latlng =
                                                        e.target.getLatLng();
                                                    setFormData((prev) => ({
                                                        ...(prev as any),
                                                        latitude:
                                                            latlng.lat.toFixed(
                                                                6,
                                                            ),
                                                        longitude:
                                                            latlng.lng.toFixed(
                                                                6,
                                                            ),
                                                    }));
                                                },
                                            }}
                                        />
                                        <SetViewOnChange
                                            coords={[
                                                Number(formData.latitude) ||
                                                    defaultCoords[0],
                                                Number(formData.longitude) ||
                                                    defaultCoords[1],
                                            ]}
                                        />
                                    </MapContainer>

                                    <div className="mt-2 flex gap-2">
                                        <Input
                                            name="latitude"
                                            type="text"
                                            value={formData.latitude ?? ''}
                                            onChange={(e) =>
                                                setFormData((prev) => ({
                                                    ...(prev as any),
                                                    latitude: e.target.value,
                                                }))
                                            }
                                            placeholder="Latitude"
                                            className="w-1/2"
                                            autoComplete="on"
                                        />
                                        <Input
                                            name="longitude"
                                            type="text"
                                            value={formData.longitude ?? ''}
                                            onChange={(e) =>
                                                setFormData((prev) => ({
                                                    ...(prev as any),
                                                    longitude: e.target.value,
                                                }))
                                            }
                                            placeholder="Longitude"
                                            className="w-1/2"
                                            autoComplete="on"
                                        />
                                    </div>
                                </div>
                            ) : (
                                <Input
                                    id={field.key}
                                    name={field.name}
                                    type={field.type}
                                    placeholder={field.placeholder}
                                    value={formData[field.key] ?? ''}
                                    onChange={(e) =>
                                        setFormData((prev) => ({
                                            ...(prev as any),
                                            [field.key]: e.target.value,
                                        }))
                                    }
                                    required={field.required}
                                    autoComplete={field.autoComplete ?? 'on'}
                                />
                            )}
                        </div>
                    ))}
                </form>

                <SheetFooter className="sticky bottom-0 border-t bg-white px-4 py-4">
                    <div className="flex gap-2">
                        <Button
                            variant="ghost"
                            type="button"
                            onClick={() => onOpenChange(false)}
                            className="flex-1"
                        >
                            Batal
                        </Button>
                        <Button
                            form="custom-form"
                            type="submit"
                            disabled={processing}
                            className="flex-1 bg-amber-200 text-primary hover:text-white"
                        >
                            {processing && (
                                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                            )}
                            {!processing
                                ? isEdit
                                    ? 'Perbarui'
                                    : 'Simpan'
                                : 'Loading...'}
                        </Button>
                    </div>
                </SheetFooter>
            </SheetContent>
        </Sheet>
    );
}
