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 { Textarea } from '@/components/ui/textarea';
import { Loader2 } from 'lucide-react';
import { useEffect, useRef, useState } from 'react';

export interface Field {
    key: string;
    name: string;
    label: string;
    type:
        | 'text'
        | 'number'
        | 'email'
        | 'select'
        | 'file'
        | 'password'
        | 'multitext';
    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;
}

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 textareasRef = useRef<Record<string, HTMLTextAreaElement | null>>({});

    const isEdit = Boolean(data);

    useEffect(() => {
        setFormData(data || ({} as T));
        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 handleTextareaChange = (
        e: React.ChangeEvent<HTMLTextAreaElement>,
        key: string,
    ) => {
        const value = e.target.value;
        setFormData((prev) => ({ ...(prev as any), [key]: value }));

        // Auto expand tinggi textarea
        const textarea = textareasRef.current[key];
        if (textarea) {
            textarea.style.height = 'auto';
            textarea.style.height = `${textarea.scrollHeight}px`;
        }
    };

    const handleSubmit = (e: React.FormEvent) => {
        e.preventDefault();
        const dataToSave: any = { ...formData };

        fields.forEach((field) => {
            if (
                field.type === 'number' &&
                dataToSave[field.key] !== undefined
            ) {
                let value = Number(dataToSave[field.key]);

                if (field.min !== undefined && value < field.min)
                    value = field.min;
                if (field.max !== undefined && value > field.max)
                    value = field.max;

                const strVal = String(value);
                if (field.minLength && strVal.length < field.minLength) {
                    value = Number(strVal.padStart(field.minLength, '0'));
                }
                if (field.maxLength && strVal.length > field.maxLength) {
                    value = Number(strVal.slice(0, field.maxLength));
                }

                dataToSave[field.key] = value;
            }
        });

        onSave(dataToSave as T);
        onOpenChange(false);
    };

    return (
        <Sheet open={open} onOpenChange={onOpenChange}>
            <SheetContent
                className="flex h-full flex-col overflow-hidden"
                onInteractOutside={(e) => e.preventDefault()}
            >
                <SheetHeader className="flex-shrink-0 border-b pb-2">
                    <SheetTitle>
                        {title}
                        <SheetDescription className="text-mute text-xs font-thin">
                            Periksa data sebelum disimpan
                        </SheetDescription>
                    </SheetTitle>
                </SheetHeader>

                {/* AREA SCROLLABLE */}
                <div className="flex-1 overflow-y-auto px-4 py-2">
                    <form id="custom-form" onSubmit={handleSubmit}>
                        {fields.map((field) => (
                            <div key={field.key} className="mb-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 selected =
                                                field.options?.find(
                                                    (opt) =>
                                                        String(opt.value) === v,
                                                );
                                            if (!selected) return;
                                            handleSelectChange(
                                                field.key,
                                                selected.value,
                                            );
                                        }}
                                    >
                                        <SelectTrigger id={field.key}>
                                            <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 === 'multitext' ? (
                                    <Textarea
                                        ref={(el) => {
                                            textareasRef.current[field.key] =
                                                el;
                                        }}
                                        id={field.key}
                                        name={field.name}
                                        placeholder={field.placeholder}
                                        value={formData[field.key] ?? ''}
                                        onChange={(e) =>
                                            handleTextareaChange(e, field.key)
                                        }
                                        required={field.required}
                                        className="min-h-24 resize-none overflow-hidden"
                                        autoComplete={
                                            field.autoComplete ?? 'off'
                                        }
                                    />
                                ) : (
                                    <Input
                                        id={field.key}
                                        name={field.name}
                                        type={
                                            field.type === 'password'
                                                ? 'password'
                                                : 'text'
                                        }
                                        placeholder={field.placeholder}
                                        value={
                                            field.type === 'number' &&
                                            formData[field.key] !== undefined
                                                ? field.numericNoFormat
                                                    ? formData[field.key]
                                                    : new Intl.NumberFormat(
                                                          'id-ID',
                                                      ).format(
                                                          formData[field.key],
                                                      )
                                                : (formData[field.key] ?? '')
                                        }
                                        maxLength={field.maxLength}
                                        onChange={(e) => {
                                            let raw = e.target.value;
                                            if (
                                                field.type === 'number' &&
                                                field.numericOnly
                                            ) {
                                                raw = raw.replace(/\D/g, '');
                                            }
                                            if (field.maxLength)
                                                raw = raw.slice(
                                                    0,
                                                    field.maxLength,
                                                );
                                            setFormData((prev) => ({
                                                ...(prev as any),
                                                [field.key]:
                                                    field.type === 'number' &&
                                                    raw !== ''
                                                        ? Number(raw)
                                                        : raw,
                                            }));
                                        }}
                                        required={field.required}
                                        autoComplete={
                                            field.autoComplete ?? 'off'
                                        }
                                    />
                                )}
                            </div>
                        ))}
                    </form>
                </div>

                {/* FOOTER TETAP DI BAWAH */}
                <SheetFooter className="flex-shrink-0 border-t bg-white px-4 py-3">
                    <div className="flex w-full gap-2">
                        <Button
                            variant="default"
                            size="sm"
                            type="button"
                            onClick={() => onOpenChange(false)}
                            className="flex-1 bg-neutral-100 text-black hover:bg-neutral-200"
                        >
                            Batal
                        </Button>
                        <Button
                            form="custom-form"
                            type="submit"
                            disabled={processing}
                            variant="default"
                            size="sm"
                            className="flex-1 bg-emerald-500 text-white hover:bg-emerald-600 hover:text-white"
                        >
                            {processing && (
                                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                            )}
                            {!processing
                                ? isEdit
                                    ? 'Perbaharui'
                                    : 'Simpan'
                                : 'Loading...'}
                        </Button>
                    </div>
                </SheetFooter>
            </SheetContent>
        </Sheet>
    );
}
