import { useForm } from '@inertiajs/react';
import { useEffect, useMemo, useState } from 'react';
import { toast } from 'sonner';
import { ConfirmActionDialog } from '@/components/confirm-action-dialog';
import { DesignationSelect } from '@/components/employees/designation-select';
import { EmployeePhoto } from '@/components/employees/employee-photo';
import { StorageFilePreview } from '@/components/employees/storage-file-preview';
import { AppDateInput } from '@/components/ui/app-date-input';
import { Button } from '@/components/ui/button';
import {
    Card,
    CardContent,
    CardDescription,
    CardHeader,
    CardTitle,
} from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
    Select,
    SelectContent,
    SelectItem,
    SelectTrigger,
    SelectValue,
} from '@/components/ui/select';
import { Spinner } from '@/components/ui/spinner';
import { Switch } from '@/components/ui/switch';
import { useLanguage } from '@/contexts/language-context';
import { useInitials } from '@/hooks/use-initials';
import { formatEmployeeJoiningDateOrDash } from '@/lib/dates';
import { EMPLOYEE_SHIFT_VALUES, normalizeEmployeeShift } from '@/lib/employee-shifts';
import { normalizeJoiningDateValue } from '@/lib/jalali-picker';
import { isImageFileUrl, resolveStorageUrl } from '@/lib/storage-files';
import { cn } from '@/lib/utils';
import { zodErrorToFieldMap } from '@/lib/zod-errors';
import { buildPermanentEmployeeSchema } from '@/validation/schemas';

function FileField({ id, label, hint, accept, error, currentUrl, currentLabel, onChange }) {
    const [pickedPreview, setPickedPreview] = useState(null);

    useEffect(() => {
        return () => {
            if (pickedPreview?.startsWith('blob:')) {
                URL.revokeObjectURL(pickedPreview);
            }
        };
    }, [pickedPreview]);

    function handleChange(e) {
        const file = e.target.files?.[0] ?? null;

        setPickedPreview((prev) => {
            if (prev?.startsWith('blob:')) {
                URL.revokeObjectURL(prev);
            }
            if (file?.type.startsWith('image/')) {
                return URL.createObjectURL(file);
            }
            return null;
        });

        onChange(e);
    }

    const previewUrl =
        pickedPreview ?? (currentUrl && isImageFileUrl(currentUrl) ? currentUrl : null);

    return (
        <div className="space-y-2">
            <Label htmlFor={id}>{label}</Label>
            {previewUrl ? (
                <StorageFilePreview
                    url={previewUrl}
                    alt={label}
                    linkLabel={currentLabel}
                    size="md"
                />
            ) : currentUrl ? (
                <StorageFilePreview
                    url={currentUrl}
                    alt={label}
                    linkLabel={currentLabel}
                    size="md"
                />
            ) : null}
            <Input
                id={id}
                name={id}
                type="file"
                accept={accept}
                className="cursor-pointer text-sm file:me-3 file:rounded-md file:border-0 file:bg-muted file:px-3 file:py-1.5 file:text-sm file:font-medium"
                onChange={handleChange}
            />
            {hint ? <p className="text-muted-foreground text-xs">{hint}</p> : null}
            {error ? <p className="text-destructive text-sm">{error}</p> : null}
        </div>
    );
}

/**
 * @param {object} props
 * @param {'create' | 'edit'} props.mode
 * @param {Record<string, string>} props.labels
 * @param {object} [props.employee]
 * @param {Array<{id: number, name: string, is_active?: boolean}>} [props.designations]
 * @param {string} props.submitUrl
 * @param {'post' | 'put'} props.submitMethod
 * @param {string} props.submitLabel
 * @param {string} props.submittingLabel
 * @param {() => void} [props.onSuccess]
 */
export function PermanentEmployeeForm({
    mode,
    labels,
    employee,
    designations = [],
    submitUrl,
    submitMethod,
    submitLabel,
    submittingLabel,
    onSuccess,
}) {
    const { t } = useLanguage();
    const p = t.employeesPermanentPage;
    const a = t.appActions;
    const getInitials = useInitials();
    const isEdit = mode === 'edit';
    const [confirmOpen, setConfirmOpen] = useState(false);

    const existingFiles = useMemo(
        () => ({
            image: Boolean(employee?.image_url),
            national_card: Boolean(employee?.national_card_url),
            health_card: Boolean(employee?.health_card_url),
            labor_card: Boolean(employee?.labor_card_url),
            contract: Boolean(employee?.contract_url),
        }),
        [employee],
    );

    const schema = useMemo(
        () =>
            buildPermanentEmployeeSchema(t.validation, {
                isEdit,
                existing: existingFiles,
            }),
        [t.validation, isEdit, existingFiles],
    );

    const form = useForm({
        full_name: employee?.full_name ?? '',
        father_name: employee?.father_name ?? '',
        national_card_number: employee?.national_card_number ?? '',
        phone_number: employee?.phone_number ?? '',
        relative_phone_number: employee?.relative_phone_number ?? '',
        address: employee?.address ?? '',
        monthly_salary: employee?.monthly_salary ?? '',
        joining_date: employee?.joining_date ?? '',
        designation_id: employee?.designation_id ?? '',
        shift: normalizeEmployeeShift(employee?.shift),
        is_active: employee?.is_active ?? true,
        image: null,
        national_card: null,
        health_card: null,
        labor_card: null,
        contract: null,
    });

    const [imagePreview, setImagePreview] = useState(
        () => resolveStorageUrl(employee?.image_url) ?? null,
    );

    useEffect(() => {
        return () => {
            if (imagePreview && imagePreview.startsWith('blob:')) {
                URL.revokeObjectURL(imagePreview);
            }
        };
    }, [imagePreview]);

    const initials = getInitials(form.data.full_name || '?');

    const docAccept =
        'image/jpeg,image/png,image/webp,.jpg,.jpeg,.png,.webp,application/pdf,.pdf';

    const shiftLabelByValue = {
        morning: labels.shiftMorning,
        night: labels.shiftNight,
    };

    const textareaClassName = cn(
        'border-input placeholder:text-muted-foreground flex min-h-[6rem] w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none md:text-sm',
        'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
        form.errors.address && 'border-destructive',
    );

    function onImageChange(e) {
        const file = e.target.files?.[0] ?? null;
        form.setData('image', file);
        setImagePreview((prev) => {
            if (prev?.startsWith('blob:')) {
                URL.revokeObjectURL(prev);
            }
            return file
                ? URL.createObjectURL(file)
                : resolveStorageUrl(employee?.image_url);
        });
    }

    function buildValidatedPayload() {
        const normalizedJoiningDate = normalizeJoiningDateValue(form.data.joining_date);
        const normalizedShift = normalizeEmployeeShift(form.data.shift);
        const candidate = {
            ...form.data,
            shift: normalizedShift,
            joining_date: normalizedJoiningDate,
        };

        const parsed = schema.safeParse(candidate);

        if (!parsed.success) {
            form.setError(zodErrorToFieldMap(parsed.error));
            return null;
        }

        if (normalizedJoiningDate !== form.data.joining_date) {
            form.setData('joining_date', normalizedJoiningDate);
        }

        if (normalizedShift !== form.data.shift) {
            form.setData('shift', normalizedShift);
        }

        return {
            ...parsed.data,
            shift: normalizeEmployeeShift(parsed.data.shift),
            image: form.data.image,
            national_card: form.data.national_card,
            health_card: form.data.health_card,
            labor_card: form.data.labor_card,
            contract: form.data.contract,
        };
    }

    function handleSubmit(e) {
        e.preventDefault();
        form.clearErrors();

        if (!buildValidatedPayload()) {
            return;
        }

        setConfirmOpen(true);
    }

    function commitSubmit() {
        form.clearErrors();

        const payload = buildValidatedPayload();
        if (!payload) {
            setConfirmOpen(false);
            return;
        }

        // Multipart PUT is not reliably parsed by PHP; POST + _method=put matches Laravel file uploads.
        form.transform((data) => {
            const body = {
                designation_id: payload.designation_id,
                full_name: payload.full_name,
                father_name: payload.father_name,
                national_card_number: payload.national_card_number,
                phone_number: payload.phone_number,
                relative_phone_number: payload.relative_phone_number ?? '',
                address: payload.address,
                monthly_salary: payload.monthly_salary,
                joining_date: payload.joining_date,
                shift: payload.shift,
                is_active: payload.is_active,
                image: data.image,
                national_card: data.national_card,
                health_card: data.health_card,
                labor_card: data.labor_card,
                contract: data.contract,
            };

            if (submitMethod === 'put') {
                body._method = 'put';
            }

            return body;
        });

        form.post(submitUrl, {
            forceFormData: true,
            preserveScroll: true,
            onSuccess,
            onError: () => toast.error(a.requestFailed),
        });
    }

    return (
        <>
            <ConfirmActionDialog
                open={confirmOpen}
                onOpenChange={setConfirmOpen}
                title={isEdit ? p.confirmUpdateTitle : p.confirmCreateTitle}
                description={isEdit ? p.confirmUpdateBody : p.confirmCreateBody}
                confirmLabel={submitLabel}
                cancelLabel={a.cancel}
                processing={form.processing}
                onConfirm={commitSubmit}
            />
            <form
                noValidate
                onSubmit={handleSubmit}
                className="mx-auto flex w-full max-w-3xl flex-col gap-6"
            >
            <Card>
                <CardHeader>
                    <CardTitle>{labels.sectionPersonal}</CardTitle>
                    <CardDescription>{labels.sectionPersonalHint}</CardDescription>
                </CardHeader>
                <CardContent className="space-y-5">
                    <div className="space-y-3">
                        <Label>{labels.image}</Label>
                        <div className="flex flex-col items-start gap-4 sm:flex-row sm:items-center">
                            <EmployeePhoto
                                src={imagePreview}
                                initials={initials}
                                size="lg"
                            />
                            <div className="grid w-full max-w-md gap-2">
                                <Input
                                    id="image"
                                    name="image"
                                    type="file"
                                    accept="image/jpeg,image/png,image/webp,.jpg,.jpeg,.png,.webp"
                                    className="cursor-pointer text-sm file:me-3 file:rounded-md file:border-0 file:bg-muted file:px-3 file:py-1.5 file:text-sm file:font-medium"
                                    onChange={onImageChange}
                                />
                                <p className="text-muted-foreground text-xs">{labels.imageHint}</p>
                                {form.errors.image ? (
                                    <p className="text-destructive text-sm">{form.errors.image}</p>
                                ) : null}
                            </div>
                        </div>
                    </div>

                    <div className="grid gap-5 sm:grid-cols-2">
                        <div className="space-y-2 sm:col-span-2">
                            <Label htmlFor="full_name">{labels.fullName}</Label>
                            <Input
                                id="full_name"
                                value={form.data.full_name}
                                onChange={(e) => form.setData('full_name', e.target.value)}
                                autoComplete="name"
                                aria-invalid={Boolean(form.errors.full_name)}
                                className={cn(form.errors.full_name && 'border-destructive')}
                            />
                            {form.errors.full_name ? (
                                <p className="text-destructive text-sm">{form.errors.full_name}</p>
                            ) : null}
                        </div>
                        <div className="space-y-2">
                            <Label htmlFor="father_name">{labels.fatherName}</Label>
                            <Input
                                id="father_name"
                                value={form.data.father_name}
                                onChange={(e) => form.setData('father_name', e.target.value)}
                                aria-invalid={Boolean(form.errors.father_name)}
                                className={cn(form.errors.father_name && 'border-destructive')}
                            />
                            {form.errors.father_name ? (
                                <p className="text-destructive text-sm">{form.errors.father_name}</p>
                            ) : null}
                        </div>
                        <div className="space-y-2">
                            <Label htmlFor="national_card_number">{labels.nationalCardNumber}</Label>
                            <Input
                                id="national_card_number"
                                value={form.data.national_card_number}
                                onChange={(e) =>
                                    form.setData('national_card_number', e.target.value)
                                }
                                aria-invalid={Boolean(form.errors.national_card_number)}
                                className={cn(
                                    form.errors.national_card_number && 'border-destructive',
                                )}
                            />
                            {form.errors.national_card_number ? (
                                <p className="text-destructive text-sm">
                                    {form.errors.national_card_number}
                                </p>
                            ) : null}
                        </div>
                    </div>
                </CardContent>
            </Card>

            <Card>
                <CardHeader>
                    <CardTitle>{labels.sectionContact}</CardTitle>
                    <CardDescription>{labels.sectionContactHint}</CardDescription>
                </CardHeader>
                <CardContent className="grid gap-5">
                    <div className="grid gap-5 sm:grid-cols-2">
                    <div className="space-y-2">
                        <Label htmlFor="phone_number">{labels.phoneNumber}</Label>
                        <Input
                            id="phone_number"
                            type="tel"
                            value={form.data.phone_number}
                            onChange={(e) => form.setData('phone_number', e.target.value)}
                            autoComplete="tel"
                            aria-invalid={Boolean(form.errors.phone_number)}
                            className={cn(form.errors.phone_number && 'border-destructive')}
                        />
                        {form.errors.phone_number ? (
                            <p className="text-destructive text-sm">{form.errors.phone_number}</p>
                        ) : null}
                    </div>
                    <div className="space-y-2">
                        <Label htmlFor="relative_phone_number">{labels.relativePhoneNumber}</Label>
                        <Input
                            id="relative_phone_number"
                            type="tel"
                            value={form.data.relative_phone_number}
                            onChange={(e) =>
                                form.setData('relative_phone_number', e.target.value)
                            }
                            autoComplete="tel"
                            aria-invalid={Boolean(form.errors.relative_phone_number)}
                            className={cn(
                                form.errors.relative_phone_number && 'border-destructive',
                            )}
                        />
                        {form.errors.relative_phone_number ? (
                            <p className="text-destructive text-sm">
                                {form.errors.relative_phone_number}
                            </p>
                        ) : null}
                    </div>
                    </div>
                    <div className="space-y-2">
                        <Label htmlFor="address">{labels.address}</Label>
                        <textarea
                            id="address"
                            rows={4}
                            value={form.data.address}
                            onChange={(e) => form.setData('address', e.target.value)}
                            aria-invalid={Boolean(form.errors.address)}
                            className={textareaClassName}
                        />
                        {form.errors.address ? (
                            <p className="text-destructive text-sm">{form.errors.address}</p>
                        ) : null}
                    </div>
                </CardContent>
            </Card>

            <Card>
                <CardHeader>
                    <CardTitle>{labels.sectionStatus}</CardTitle>
                    <CardDescription>{labels.sectionStatusHint}</CardDescription>
                </CardHeader>
                <CardContent>
                    <div className="flex items-center justify-between gap-4 rounded-lg border border-border px-4 py-3">
                        <div className="space-y-0.5">
                            <Label htmlFor="is_active">{labels.isActive}</Label>
                            <p className="text-muted-foreground text-xs">{labels.isActiveHint}</p>
                        </div>
                        <Switch
                            id="is_active"
                            checked={form.data.is_active}
                            onCheckedChange={(checked) => form.setData('is_active', checked)}
                        />
                    </div>
                    {form.errors.is_active ? (
                        <p className="text-destructive mt-2 text-sm">{form.errors.is_active}</p>
                    ) : null}
                </CardContent>
            </Card>

            <Card>
                <CardHeader>
                    <CardTitle>{labels.sectionEmployment}</CardTitle>
                    {labels.sectionEmploymentHint ? (
                        <CardDescription>{labels.sectionEmploymentHint}</CardDescription>
                    ) : null}
                </CardHeader>
                <CardContent className="grid gap-5 sm:grid-cols-2">
                    <div className="sm:col-span-2">
                        <DesignationSelect
                            designations={designations}
                            value={form.data.designation_id}
                            onValueChange={(value) => {
                                form.setData('designation_id', Number(value));
                                if (form.errors.designation_id) {
                                    form.clearErrors('designation_id');
                                }
                            }}
                            labels={labels}
                            error={form.errors.designation_id}
                        />
                    </div>
                    <div className="space-y-2">
                        <Label htmlFor="shift">{labels.shift}</Label>
                        <Select
                            value={normalizeEmployeeShift(form.data.shift)}
                            onValueChange={(value) => {
                                form.setData('shift', normalizeEmployeeShift(value));
                                if (form.errors.shift) {
                                    form.clearErrors('shift');
                                }
                            }}
                        >
                            <SelectTrigger
                                id="shift"
                                aria-invalid={Boolean(form.errors.shift)}
                                className={cn(form.errors.shift && 'border-destructive')}
                            >
                                <SelectValue placeholder={labels.shiftPlaceholder} />
                            </SelectTrigger>
                            <SelectContent>
                                {EMPLOYEE_SHIFT_VALUES.map((value) => (
                                    <SelectItem key={value} value={value}>
                                        {shiftLabelByValue[value] ?? value}
                                    </SelectItem>
                                ))}
                            </SelectContent>
                        </Select>
                        {form.errors.shift ? (
                            <p className="text-destructive text-sm">{form.errors.shift}</p>
                        ) : null}
                    </div>
                    <div className="space-y-2">
                        <Label htmlFor="monthly_salary">{labels.monthlySalary}</Label>
                        <Input
                            id="monthly_salary"
                            type="number"
                            min="0"
                            step="0.01"
                            value={form.data.monthly_salary}
                            onChange={(e) => form.setData('monthly_salary', e.target.value)}
                            aria-invalid={Boolean(form.errors.monthly_salary)}
                            className={cn(form.errors.monthly_salary && 'border-destructive')}
                        />
                        {labels.monthlySalaryHint ? (
                            <p className="text-muted-foreground text-xs">{labels.monthlySalaryHint}</p>
                        ) : null}
                        {form.errors.monthly_salary ? (
                            <p className="text-destructive text-sm">{form.errors.monthly_salary}</p>
                        ) : null}
                    </div>
                    <div className="space-y-2">
                        <Label htmlFor="joining_date">{labels.joiningDate}</Label>
                        <AppDateInput
                            id="joining_date"
                            forceJalali
                            value={form.data.joining_date}
                            onChange={(next) => {
                                form.setData(
                                    'joining_date',
                                    next,
                                );
                                if (form.errors.joining_date) {
                                    form.clearErrors('joining_date');
                                }
                            }}
                            invalid={Boolean(form.errors.joining_date)}
                        />
                        {form.errors.joining_date ? (
                            <p className="text-destructive text-sm">{form.errors.joining_date}</p>
                        ) : null}
                        {form.data.joining_date ? (
                            <p className="text-muted-foreground text-xs">
                                {labels.joiningDateDisplay}:{' '}
                                {formatEmployeeJoiningDateOrDash(form.data.joining_date)}
                            </p>
                        ) : null}
                    </div>
                </CardContent>
            </Card>

            <Card>
                <CardHeader>
                    <CardTitle>{labels.sectionDocuments}</CardTitle>
                    <CardDescription>
                        {isEdit ? labels.sectionDocumentsEditHint : labels.sectionDocumentsHint}
                    </CardDescription>
                </CardHeader>
                <CardContent className="grid gap-5 sm:grid-cols-2">
                    <FileField
                        id="national_card"
                        label={labels.nationalCard}
                        hint={labels.documentHint}
                        accept={docAccept}
                        error={form.errors.national_card}
                        currentUrl={employee?.national_card_url}
                        currentLabel={labels.viewCurrentFile}
                        onChange={(e) =>
                            form.setData('national_card', e.target.files?.[0] ?? null)
                        }
                    />
                    <FileField
                        id="health_card"
                        label={labels.healthCard}
                        hint={labels.documentHint}
                        accept={docAccept}
                        error={form.errors.health_card}
                        currentUrl={employee?.health_card_url}
                        currentLabel={labels.viewCurrentFile}
                        onChange={(e) =>
                            form.setData('health_card', e.target.files?.[0] ?? null)
                        }
                    />
                    <FileField
                        id="labor_card"
                        label={labels.laborCard}
                        hint={labels.documentHint}
                        accept={docAccept}
                        error={form.errors.labor_card}
                        currentUrl={employee?.labor_card_url}
                        currentLabel={labels.viewCurrentFile}
                        onChange={(e) =>
                            form.setData('labor_card', e.target.files?.[0] ?? null)
                        }
                    />
                    <FileField
                        id="contract"
                        label={labels.contract}
                        hint={labels.documentHint}
                        accept={docAccept}
                        error={form.errors.contract}
                        currentUrl={employee?.contract_url}
                        currentLabel={labels.viewCurrentFile}
                        onChange={(e) =>
                            form.setData('contract', e.target.files?.[0] ?? null)
                        }
                    />
                </CardContent>
            </Card>

            <div className="flex flex-wrap items-center gap-3 pb-4">
                <Button type="submit" disabled={form.processing} className="gap-2">
                    {form.processing ? <Spinner /> : null}
                    {form.processing ? submittingLabel : submitLabel}
                </Button>
            </div>
        </form>
        </>
    );
}
