import { router } from '@inertiajs/react';
import { CheckSquare, Loader2, Pencil } from 'lucide-react';
import { useEffect, useState } from 'react';
import { toast } from 'sonner';

import { Button } from '@/components/ui/button';
import { DateTimePicker } from '@/components/ui/datetime-picker';
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 { useYupValidation } from '@/hooks/use-yup-validation';
import { myTaskStatusBlockReason } from '@/lib/my-task-status';
import { personalTaskSchema } from '@/lib/validation/task';
import { store, update } from '@/routes/personal-tasks';
import type { MyTask, MyTaskPriority, MyTaskStatus } from '@/types/my-task';

const STATUS_OPTIONS: { value: MyTaskStatus; label: string }[] = [
    { value: 'todo', label: 'To Do' },
    { value: 'in_progress', label: 'In Progress' },
    { value: 'done', label: 'Done' },
];

interface MyTaskFormSheetProps {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    /** Task yang diedit. Null berarti membuat task baru. */
    task?: MyTask | null;
    /** Diisi saat menambah subtask ke sebuah task induk. */
    parentId?: number | null;
    /** Status task induk saat yang diedit adalah subtask. */
    parentStatus?: MyTaskStatus | null;
}

function formatDateForInput(dateString?: string | null) {
    if (!dateString) {
        return '';
    }

    const date = new Date(dateString);

    if (Number.isNaN(date.getTime())) {
        return '';
    }

    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');

    return `${year}-${month}-${day}T${hours}:${minutes}`;
}

function formDataFor(task: MyTask | null) {
    return {
        title: task?.title ?? '',
        note: task?.note ?? '',
        status: (task?.status ?? 'todo') as MyTaskStatus,
        priorityLevel: (task?.priority_level.toString() ??
            '2') as `${MyTaskPriority}`,
        dueDate: formatDateForInput(task?.due_date),
    };
}

/**
 * Pembungkus sheet. Isinya di-remount lewat `key` tiap kali task yang dibuka
 * berganti, sehingga form selalu mulai dari nilai yang benar tanpa perlu
 * menyinkronkan state lewat effect.
 */
export function MyTaskFormSheet({
    open,
    onOpenChange,
    task = null,
    parentId = null,
    parentStatus = null,
}: MyTaskFormSheetProps) {
    return (
        <Sheet open={open} onOpenChange={onOpenChange}>
            <SheetContent
                className="flex h-full w-full flex-col gap-0 overflow-hidden bg-background p-0 sm:max-w-lg"
                hideClose
            >
                <MyTaskForm
                    key={
                        task
                            ? `edit-${task.id}`
                            : `create-${parentId ?? 'root'}`
                    }
                    task={task}
                    parentId={parentId}
                    parentStatus={parentStatus}
                    onClose={() => onOpenChange(false)}
                />
            </SheetContent>
        </Sheet>
    );
}

function MyTaskForm({
    task,
    parentId,
    parentStatus,
    onClose,
}: {
    task: MyTask | null;
    parentId: number | null;
    parentStatus: MyTaskStatus | null;
    onClose: () => void;
}) {
    const isEditing = task !== null;
    const [processing, setProcessing] = useState(false);
    const [formData, setFormData] = useState(() => formDataFor(task));

    // Form ini di-remount lewat `key` tiap ganti task, jadi pesan error ikut
    // hilang sendiri — tidak perlu direset manual.
    const { errors, validateField, clearError, validate } = useYupValidation(
        personalTaskSchema,
        formData,
    );

    useEffect(() => {
        setFormData(formDataFor(task));
    }, [task]);

    // Penjagaan hierarki di server hanya berlaku saat mengubah baris yang
    // sudah ada; aturan deadline berlaku juga saat membuat. Konteks di bawah
    // meniru pembagian itu supaya form tidak mematikan pilihan yang sebenarnya
    // akan diterima server.
    const blockedStatusReasons = Object.fromEntries(
        STATUS_OPTIONS.map(({ value }) => [
            value,
            myTaskStatusBlockReason(value, {
                isSubtask: isEditing && task.parent_id !== null,
                parentStatus,
                hasDueDate: formData.dueDate !== '',
                openSubtaskCount: isEditing
                    ? (task.subtasks ?? []).filter((s) => s.status !== 'done')
                          .length
                    : 0,
            }),
        ]),
    ) as Record<MyTaskStatus, string | null>;

    const activeStatusReason = blockedStatusReasons[formData.status];

    const handleSubmit = (event: React.FormEvent) => {
        event.preventDefault();

        if (!validate()) {
            return;
        }

        const payload = {
            title: formData.title.trim(),
            note: formData.note.trim() || null,
            status: formData.status,
            priority_level: Number(formData.priorityLevel),
            due_date: formData.dueDate || null,
            ...(isEditing ? {} : { parent_id: parentId }),
        };

        const options = {
            preserveScroll: true,
            onBefore: () => setProcessing(true),
            onFinish: () => setProcessing(false),
            onSuccess: () => {
                toast.success(isEditing ? 'Task updated' : 'Task created');
                onClose();
            },
            onError: (errors: Record<string, string>) => {
                toast.error(Object.values(errors)[0] ?? 'Failed to save task');
            },
        };

        if (isEditing) {
            router.put(update(task.id).url, payload, options);

            return;
        }

        router.post(store().url, payload, options);
    };

    const sheetTitle = isEditing
        ? 'Edit Task'
        : parentId
          ? 'Add Subtask'
          : 'Create Task';

    return (
        <form
            onSubmit={handleSubmit}
            className="flex h-full flex-col space-y-0"
            noValidate
        >
            <SheetHeader className="border-b p-6 text-left">
                <SheetTitle className="flex items-center gap-2">
                    {isEditing ? (
                        <Pencil className="h-4 w-4" />
                    ) : (
                        <CheckSquare className="h-4 w-4" />
                    )}
                    {sheetTitle}
                </SheetTitle>
                <SheetDescription>
                    This task is only visible to you.
                </SheetDescription>
            </SheetHeader>

            <div className="flex-1 space-y-4 overflow-y-auto p-6">
                <div className="space-y-2">
                    <Label htmlFor="my-task-title">Task Title</Label>
                    <Input
                        id="my-task-title"
                        placeholder="What needs to be done?"
                        value={formData.title}
                        onChange={(e) => {
                            setFormData((prev) => ({
                                ...prev,
                                title: e.target.value,
                            }));
                            clearError('title');
                        }}
                        onBlur={() => validateField('title')}
                        maxLength={255}
                        autoFocus
                        required
                    />
                    {errors.title && (
                        <p className="text-xs text-destructive">
                            {errors.title}
                        </p>
                    )}
                </div>

                <div className="space-y-2">
                    <Label htmlFor="my-task-note">Description</Label>
                    <Textarea
                        id="my-task-note"
                        placeholder="Additional details (optional)"
                        value={formData.note}
                        onChange={(e) => {
                            setFormData((prev) => ({
                                ...prev,
                                note: e.target.value,
                            }));
                            clearError('note');
                        }}
                        onBlur={() => validateField('note')}
                        className="min-h-30 resize-none"
                        maxLength={10000}
                    />
                    {errors.note && (
                        <p className="text-xs text-destructive">
                            {errors.note}
                        </p>
                    )}
                </div>

                <div className="grid gap-4 sm:grid-cols-2">
                    <div className="space-y-2">
                        <Label id="my-task-status-label">Status</Label>
                        <Select
                            value={formData.status}
                            onValueChange={(value) =>
                                setFormData((prev) => ({
                                    ...prev,
                                    status: value as MyTaskStatus,
                                }))
                            }
                        >
                            <SelectTrigger
                                className="w-full"
                                aria-labelledby="my-task-status-label"
                            >
                                <SelectValue />
                            </SelectTrigger>
                            <SelectContent>
                                {STATUS_OPTIONS.map(({ value, label }) => (
                                    <SelectItem
                                        key={value}
                                        value={value}
                                        disabled={
                                            blockedStatusReasons[value] !== null
                                        }
                                    >
                                        {label}
                                    </SelectItem>
                                ))}
                            </SelectContent>
                        </Select>
                        {activeStatusReason && (
                            <p className="text-xs text-muted-foreground">
                                {activeStatusReason}
                            </p>
                        )}
                    </div>

                    <div className="space-y-2">
                        <Label id="my-task-priority-label">Priority</Label>
                        <Select
                            value={formData.priorityLevel}
                            onValueChange={(value) =>
                                setFormData((prev) => ({
                                    ...prev,
                                    priorityLevel: value as `${MyTaskPriority}`,
                                }))
                            }
                        >
                            <SelectTrigger
                                className="w-full"
                                aria-labelledby="my-task-priority-label"
                            >
                                <SelectValue />
                            </SelectTrigger>
                            <SelectContent>
                                <SelectItem value="1">Low</SelectItem>
                                <SelectItem value="2">Medium</SelectItem>
                                <SelectItem value="3">High</SelectItem>
                                <SelectItem value="4">Urgent</SelectItem>
                            </SelectContent>
                        </Select>
                    </div>
                </div>

                <div className="space-y-2">
                    <Label id="my-task-due-label">Deadline (optional)</Label>
                    <DateTimePicker
                        ariaLabelledBy="my-task-due-label"
                        value={formData.dueDate}
                        onChange={(value) =>
                            setFormData((prev) => ({
                                ...prev,
                                dueDate: value,
                            }))
                        }
                        placeholder="Pick a deadline date & time"
                    />
                </div>
            </div>

            <SheetFooter className="border-t p-6">
                <div className="flex w-full gap-3 sm:justify-end">
                    <Button
                        type="button"
                        variant="outline"
                        onClick={onClose}
                        className="flex-1 sm:flex-none"
                        disabled={processing}
                    >
                        Cancel
                    </Button>
                    {/* Status terpilih bisa berubah jadi terlarang tanpa
                        menyentuh dropdown — misalnya deadline dikosongkan
                        selagi "In Progress" aktif. Simpan ikut dimatikan agar
                        penolakannya tidak baru muncul setelah dikirim. */}
                    <Button
                        type="submit"
                        disabled={processing || activeStatusReason !== null}
                        className="flex-1 sm:flex-none"
                    >
                        {processing ? (
                            <>
                                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                                {isEditing ? 'Saving...' : 'Creating...'}
                            </>
                        ) : isEditing ? (
                            'Save Changes'
                        ) : (
                            'Create Task'
                        )}
                    </Button>
                </div>
            </SheetFooter>
        </form>
    );
}
