import ComboBoxInput from '@/Components/ComboBoxInput';
import FormInput from '@/Components/FormInput';
import PrimaryButton from '@/Components/PrimaryButton';
import SelectInput from '@/Components/SelectInput';
import TextInput from '@/Components/TextInput';
import {
    Sheet,
    SheetContent,
    SheetDescription,
    SheetHeader,
    SheetTitle,
    SheetTrigger,
} from '@/Components/ui/sheet';
import { ACCEPTED_FILE_EXTENSIONS } from '@/Pages/Document/documentFile';
import { t } from '@/lib/utils';
import { DocumentType, User } from '@/types';
import { useForm } from '@inertiajs/react';
import axios from 'axios';
import { Loader2 } from 'lucide-react';
import React, { ChangeEvent, FormEventHandler, useState } from 'react';

// Sentinel option letting the user type a type that does not exist yet.
const NEW_TYPE_VALUE = 'new';

interface DocumentCreateFormProps {
    documentTypes: DocumentType[];
}

interface DocumentFormData {
    user: User | null;
    file: File | null;
    name: string;
    document_type_id: string;
    document_type_name: string;
}

export default function DocumentCreateForm({
    documentTypes,
}: DocumentCreateFormProps) {
    const [open, setOpen] = React.useState(false);
    const [availableUsers, setAvailableUsers] = useState<User[]>([]);

    const { data, setData, post, processing, errors, reset, transform } =
        useForm<DocumentFormData>({
            user: null,
            file: null,
            name: '',
            document_type_id: String(documentTypes[0]?.id ?? ''),
            document_type_name: '',
        });
    const formErrors = errors as Record<string, string>;

    const creatingNewType = data.document_type_id === NEW_TYPE_VALUE;

    const typeOptions = [
        ...documentTypes.map((documentType) => ({
            value: String(documentType.id),
            label: documentType.name,
        })),
        { value: NEW_TYPE_VALUE, label: 'Nuova tipologia…' },
    ];

    const submit: FormEventHandler = (e) => {
        e.preventDefault();

        transform(
            (data) =>
                ({
                    ...data,
                    user_id: data.user ? data.user.id : null,
                    document_type_id: creatingNewType
                        ? null
                        : data.document_type_id,
                    document_type_name: creatingNewType
                        ? data.document_type_name
                        : null,
                }) as unknown as DocumentFormData,
        );

        post(route('documents.create'), {
            forceFormData: true,
            onSuccess: () => {
                setOpen(false);
                reset();
            },
        });
    };

    // Pre-fill the document name with the file name, the user can still edit it.
    const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
        const file = e.target.files?.[0] ?? null;

        setData((previous) => ({
            ...previous,
            file,
            name: previous.name || (file ? file.name : ''),
        }));
    };

    const fetchUsers = async (search: string) => {
        try {
            const response = await axios.get(route('search-users'), {
                params: { search },
            });
            setAvailableUsers(response.data);
        } catch (error) {
            console.error('Error fetching items:', error);
        }
    };

    return (
        <Sheet open={open} onOpenChange={setOpen}>
            <SheetTrigger asChild>
                <PrimaryButton>Aggiungi</PrimaryButton>
            </SheetTrigger>
            <SheetContent side="right" className="overflow-auto">
                <SheetHeader>
                    <SheetTitle>Nuovo documento</SheetTitle>
                    <SheetDescription>
                        <form onSubmit={submit}>
                            <FormInput
                                label="Utente"
                                id="user_id"
                                className="mt-8 block w-full"
                                error={formErrors.user_id}
                            >
                                <ComboBoxInput
                                    value={data.user}
                                    options={availableUsers}
                                    renderOption={(user) =>
                                        `${user.name} ${user.surname}`
                                    }
                                    onChange={(value) => setData('user', value)}
                                    onSearchChange={fetchUsers}
                                />
                            </FormInput>
                            <FormInput
                                label="File"
                                id="file"
                                className="mt-8 block w-full"
                                error={formErrors.file}
                            >
                                <input
                                    type="file"
                                    accept={ACCEPTED_FILE_EXTENSIONS}
                                    onChange={handleFileChange}
                                    className="block w-full rounded-md border border-neutral-200 p-2 text-sm text-neutral-900 file:mr-4 file:rounded-md file:border-0 file:bg-neutral-100 file:px-3 file:py-1 file:text-sm"
                                />
                            </FormInput>
                            <FormInput
                                label="Nome del file"
                                id="name"
                                className="mt-8 block w-full"
                                error={formErrors.name}
                            >
                                <TextInput
                                    value={data.name}
                                    onChange={(e) =>
                                        setData('name', e.target.value)
                                    }
                                />
                            </FormInput>
                            <FormInput
                                label="Tipologia"
                                id="document_type_id"
                                className="mt-8 block w-full"
                                error={formErrors.document_type_id}
                            >
                                <SelectInput
                                    options={typeOptions}
                                    value={data.document_type_id}
                                    onChange={(value) =>
                                        setData('document_type_id', value)
                                    }
                                />
                            </FormInput>
                            {creatingNewType ? (
                                <FormInput
                                    label="Nome della nuova tipologia"
                                    id="document_type_name"
                                    className="mt-8 block w-full"
                                    error={formErrors.document_type_name}
                                >
                                    <TextInput
                                        value={data.document_type_name}
                                        onChange={(e) =>
                                            setData(
                                                'document_type_name',
                                                e.target.value,
                                            )
                                        }
                                    />
                                </FormInput>
                            ) : null}

                            <div className="mt-20 flex items-center justify-end">
                                <PrimaryButton
                                    className="ms-4"
                                    disabled={processing}
                                >
                                    {processing ? (
                                        <Loader2 className="animate-spin" />
                                    ) : null}
                                    {t('Save')}
                                </PrimaryButton>
                            </div>
                        </form>
                    </SheetDescription>
                </SheetHeader>
            </SheetContent>
        </Sheet>
    );
}
