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

import {
    REQUIRED_PROOF_OPTIONS,
    RequiredProofField,
} from '@/components/tasks/RequiredProofField';
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 { mainTaskFormSchema, taskFormSchema } from '@/lib/validation/task';
import { update } from '@/routes/tasks/tasks';
import type { Status, Task } from '@/types/task';

interface EditTaskSheetProps {
    task: Task | null;
    open: boolean;
    onOpenChange: (open: boolean) => void;
    withoutProject?: boolean;
    projects: {
        id: string;
        name: string;
        divisionId: string;
        members: { id: string; name: string; role?: string }[];
    }[];
    divisionMembers?: { id: string; name: string; role?: string }[];
    onSuccess?: () => void;
}

export function EditTaskSheet({
    task,
    open,
    onOpenChange,
    withoutProject = false,
    projects,
    divisionMembers = [],
    onSuccess,
}: EditTaskSheetProps) {
    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-3xl"
                hideClose
            >
                {task && (
                    <EditTaskForm
                        key={task.id}
                        task={task}
                        projects={projects}
                        divisionMembers={divisionMembers}
                        withoutProject={withoutProject}
                        onClose={() => onOpenChange(false)}
                        onSuccess={onSuccess}
                    />
                )}
            </SheetContent>
        </Sheet>
    );
}

function EditTaskForm({
    task,
    projects,
    divisionMembers,
    withoutProject,
    onClose,
    onSuccess,
}: {
    task: Task;
    projects: {
        id: string;
        name: string;
        divisionId: string;
        members: { id: string; name: string; role?: string }[];
    }[];
    divisionMembers: { id: string; name: string; role?: string }[];
    withoutProject: boolean;
    onClose: () => void;
    onSuccess?: () => void;
}) {
    const formatDateForInput = (dateString?: string | null) => {
        if (!dateString) {
            return '';
        }

        try {
            const date = new Date(dateString);

            if (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}`;
        } catch {
            return '';
        }
    };

    // Pemanggil lintas project (dashboard) tidak mengirim daftar anggota konteks:
    // satu daftar di sana mencampur banyak project, jadi tidak ada satu konteks
    // yang benar untuk dikirim. Tanpa jaring pengaman, dropdown "Assign To"
    // tampil kosong — terlihat seperti data yang belum dimuat — dan menyimpan
    // mengirim `assignee_ids: []`, yang di server berarti "lepas semua", bukan
    // "tidak diisi". Pelaksana yang sudah terpasang karena itu dipakai sebagai
    // daftar minimum; menggantinya dengan orang lain tetap menuntut konteks yang
    // lengkap. Pola yang sama sudah dipakai `TaskDetailSheet` untuk subtask.
    const currentAssigneeMembers: {
        id: string;
        name: string;
        role?: string;
    }[] = (task.assignees ?? []).map((user) => ({
        id: String(user.id),
        name: user.name,
    }));
    const withFallback = (
        members: { id: string; name: string; role?: string }[],
    ) => (members.length ? members : currentAssigneeMembers);

    const contextMembers = withFallback(
        withoutProject
            ? divisionMembers
            : (projects.find((p) => String(p.id) === String(task.projectId))
                  ?.members ?? []),
    );
    const validInitialAssigneeIds = new Set(
        contextMembers.map((member) => String(member.id)),
    );

    // Nilai awal projectId dipakai dua kali — mengisi form dan menjadi
    // pembanding `isDirty`. Dulu keduanya dihitung terpisah, dan di konteks
    // tanpa project (`withoutProject`) pembandingnya tetap `String(task.projectId)`
    // sehingga form dianggap kotor sejak dibuka.
    const initialProjectId = withoutProject ? '' : String(task.projectId);
    // `TaskResource` memetakan kolom NULL menjadi `'none'`, nilai yang ditolak
    // `Rule::in` saat disimpan. Dipulangkan ke string kosong agar tampil sebagai
    // "belum dipilih" dan tertahan validasi klien, bukan diam-diam berubah jadi
    // 'file' — yang berarti mengubah persyaratan task tanpa diminta.
    const initialRequiredProofType = REQUIRED_PROOF_OPTIONS.some(
        (option) => option.value === task.requiredProofType,
    )
        ? String(task.requiredProofType)
        : '';

    const [processing, setProcessing] = useState(false);
    const [formData, setFormData] = useState({
        title: task.title,
        description: task.description || '',
        projectId: initialProjectId,
        priorityLevel: task.priorityLevel?.toString() || '2',
        status: task.status,
        dueDate: formatDateForInput(task.dueDate),
        // Task lama bisa punya banyak assignee; ambil yang pertama saja karena
        // flow sekarang hanya mengizinkan satu pelaksana.
        assigneeId:
            (task.assigneeIds || [])
                .map(String)
                .find((id) => validInitialAssigneeIds.has(id)) || '',
        requiredProofType: initialRequiredProofType,
    });

    const { errors, validateField, clearError, validate } = useYupValidation(
        // Subtask mewarisi bukti dari induknya dan mengirim `null`, jadi hanya
        // task utama yang wajib menetapkan jenis bukti.
        task.parentId ? taskFormSchema : mainTaskFormSchema,
        formData,
    );

    const selectedProject = withoutProject
        ? null
        : projects.find((p) => String(p.id) === String(formData.projectId));
    // Viewer tidak bisa ditugaskan task, jadi tidak ditawarkan. Pelaksana yang
    // sudah terpasang dikecualikan: task lama bisa saja masih dipegang viewer
    // dari sebelum aturan ini ada, dan menyaringnya keluar akan melepas
    // pelaksananya diam-diam begitu task disimpan.
    const currentAssigneeIds = new Set((task.assigneeIds || []).map(String));
    const assigneeOptions = withFallback(
        withoutProject ? divisionMembers : (selectedProject?.members ?? []),
    ).filter(
        (member) =>
            member.role !== 'viewer' ||
            currentAssigneeIds.has(String(member.id)),
    );
    const validAssigneeIds = new Set(
        assigneeOptions.map((member) => String(member.id)),
    );

    const initialAssigneeId =
        (task.assigneeIds || [])
            .map(String)
            .find((id) => validInitialAssigneeIds.has(id)) || '';

    const isDirty =
        formData.title !== task.title ||
        formData.description !== (task.description || '') ||
        formData.projectId !== initialProjectId ||
        formData.priorityLevel !== (task.priorityLevel?.toString() || '2') ||
        formData.status !== task.status ||
        formData.dueDate !== formatDateForInput(task.dueDate) ||
        formData.assigneeId !== initialAssigneeId ||
        formData.requiredProofType !== initialRequiredProofType;

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

        if (!validate()) {
            return;
        }

        const assigneeIds =
            formData.assigneeId && validAssigneeIds.has(formData.assigneeId)
                ? [formData.assigneeId]
                : [];

        router.put(
            update({ task: task.code }).url,
            {
                division_id:
                    selectedProject?.divisionId ||
                    projects[0]?.divisionId ||
                    task.divisionId,
                project_id: withoutProject ? null : formData.projectId,
                recurring_task_id: task.recurringTaskId ?? null,
                name: formData.title,
                description: formData.description,
                status: formData.status,
                due_date: formData.dueDate,
                priority_level: parseInt(formData.priorityLevel) || 1,
                required_proof_type: task.parentId
                    ? null
                    : formData.requiredProofType,
                assignee_ids: assigneeIds,
            },
            {
                onBefore: () => setProcessing(true),
                onFinish: () => setProcessing(false),
                onSuccess: () => {
                    toast.success('Task updated');
                    onClose();
                    onSuccess?.();
                },
                onError: (errors) => {
                    console.error('Update errors:', errors);
                    toast.error(
                        Object.values(errors)[0] || 'Failed to update 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">
                    <Pencil className="h-4 w-4" />
                    Edit Task
                </SheetTitle>
                <SheetDescription>
                    Update your task details and project workflow.
                </SheetDescription>
            </SheetHeader>

            <div className="flex-1 space-y-4 overflow-y-auto p-6">
                {!withoutProject && (
                    <div className="space-y-2">
                        <Label>Project</Label>
                        <Select
                            disabled
                            value={formData.projectId}
                            onValueChange={(val) =>
                                setFormData({
                                    ...formData,
                                    projectId: val,
                                    assigneeId: '',
                                })
                            }
                        >
                            <SelectTrigger className="w-full">
                                <SelectValue placeholder="Select project" />
                            </SelectTrigger>
                            <SelectContent>
                                {projects.map((p) => (
                                    <SelectItem
                                        key={p.id}
                                        value={p.id.toString()}
                                    >
                                        {p.name}
                                    </SelectItem>
                                ))}
                            </SelectContent>
                        </Select>
                    </div>
                )}

                <div className="space-y-2">
                    <Label>Assign To</Label>
                    <Select
                        value={formData.assigneeId}
                        onValueChange={(val) =>
                            setFormData({
                                ...formData,
                                assigneeId: val,
                            })
                        }
                        disabled={withoutProject ? false : !formData.projectId}
                    >
                        <SelectTrigger className="w-full">
                            <SelectValue
                                placeholder={
                                    withoutProject || formData.projectId
                                        ? 'Select an assignee'
                                        : 'Select a project first'
                                }
                            />
                        </SelectTrigger>
                        <SelectContent>
                            {assigneeOptions.map((m) => (
                                <SelectItem key={m.id} value={m.id.toString()}>
                                    {m.name}
                                </SelectItem>
                            ))}
                        </SelectContent>
                    </Select>
                </div>

                <div className="space-y-2">
                    <Label htmlFor="edit-title">Task Title</Label>
                    <Input
                        id="edit-title"
                        value={formData.title}
                        onChange={(e) => {
                            setFormData({
                                ...formData,
                                title: e.target.value,
                            });
                            clearError('title');
                        }}
                        onBlur={() => validateField('title')}
                        placeholder="Name the task briefly, e.g. Send invoice to client"
                        required
                    />
                    {errors.title && (
                        <p className="text-xs text-destructive">
                            {errors.title}
                        </p>
                    )}
                </div>

                <div className="space-y-2">
                    <Label htmlFor="edit-description">Description</Label>
                    <Textarea
                        id="edit-description"
                        placeholder="Describe the work here — steps, notes, or anything the assignee needs to know"
                        value={formData.description}
                        onChange={(e) =>
                            setFormData({
                                ...formData,
                                description: e.target.value,
                            })
                        }
                        className="min-h-30 resize-none"
                    />
                </div>

                <div className="space-y-2">
                    <Label>Status</Label>
                    <Select
                        value={formData.status}
                        onValueChange={(val) =>
                            setFormData({
                                ...formData,
                                status: val as Status,
                            })
                        }
                    >
                        <SelectTrigger className="w-full">
                            <SelectValue placeholder="Select status" />
                        </SelectTrigger>
                        <SelectContent>
                            <SelectItem value="waiting">Waiting</SelectItem>
                            <SelectItem value="in_progress">
                                In Progress
                            </SelectItem>
                            {!task.parentId && (
                                <SelectItem value="review">Review</SelectItem>
                            )}
                            <SelectItem value="completed">Completed</SelectItem>
                            <SelectItem value="on_hold">On Hold</SelectItem>
                            <SelectItem value="cancelled">Cancelled</SelectItem>
                        </SelectContent>
                    </Select>
                </div>

                <div className="space-y-2">
                    <Label>Priority</Label>
                    <Select
                        value={formData.priorityLevel}
                        onValueChange={(val) =>
                            setFormData({
                                ...formData,
                                priorityLevel: val,
                            })
                        }
                    >
                        <SelectTrigger className="w-full">
                            <SelectValue placeholder="Select priority" />
                        </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 className="space-y-2">
                    <Label id="edit-task-deadline-label">
                        Deadline
                        {formData.assigneeId && (
                            <span
                                className="text-destructive"
                                aria-hidden="true"
                            >
                                {' '}
                                *
                            </span>
                        )}
                    </Label>
                    <DateTimePicker
                        ariaLabelledBy="edit-task-deadline-label"
                        ariaDescribedBy={
                            errors.dueDate
                                ? 'edit-task-deadline-error'
                                : undefined
                        }
                        ariaInvalid={Boolean(errors.dueDate)}
                        value={formData.dueDate}
                        onChange={(val) => {
                            setFormData({
                                ...formData,
                                dueDate: val,
                            });
                            clearError('dueDate');
                        }}
                        placeholder="Pick a deadline date & time"
                    />
                    {errors.dueDate && (
                        <p
                            id="edit-task-deadline-error"
                            aria-live="polite"
                            className="text-xs text-destructive"
                        >
                            {errors.dueDate}
                        </p>
                    )}
                </div>

                {!task.parentId && (
                    <RequiredProofField
                        value={formData.requiredProofType}
                        onChange={(requiredProofType) => {
                            setFormData({ ...formData, requiredProofType });
                            clearError('requiredProofType');
                        }}
                        error={errors.requiredProofType}
                    />
                )}
            </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>
                    <Button
                        type="submit"
                        disabled={processing || !isDirty}
                        className="flex-1 sm:flex-none"
                    >
                        {processing ? (
                            <>
                                <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                                Saving...
                            </>
                        ) : (
                            'Save Changes'
                        )}
                    </Button>
                </div>
            </SheetFooter>
        </form>
    );
}
