import { DeleteConfirmDialog } from '@/components/delete-confirm-dialog';
import { FormDialog } from '@/components/form-dialog';
import InputError from '@/components/input-error';
import { PageHeader } from '@/components/page-header';
import { RowActions } from '@/components/row-actions';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { Card, CardContent, 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 { usePermissions } from '@/hooks/use-permissions';
import { cn } from '@/lib/utils';
import {
    destroy,
    store,
    update,
} from '@/routes/admin/academic-classes/schedules';
import type { Schedule } from '@/types/schedule';
import { DayOfWeekLabels, DaysOfWeek } from '@/types/schedule';
import { Head, router } from '@inertiajs/react';
import { Clock, MapPin, Pencil, Plus, Trash2, Video } from 'lucide-react';
import { useState } from 'react';

type CourseClassOption = {
    id: number;
    course: { id: number; code: string; name: string } | null;
};

type Props = {
    schedules: Schedule[];
    courseClasses: CourseClassOption[];
    highlight?: number;
};

const UNSCHEDULED = '__unscheduled__';

const BOARD_COLUMNS = [...DaysOfWeek, UNSCHEDULED] as const;

function courseClassLabel(courseClass: CourseClassOption): string {
    return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
}

function toTimeInput(value: string | null): string {
    return value ? value.slice(0, 5) : '';
}

export default function ScheduleIndex({
    schedules,
    courseClasses,
    highlight,
}: Props) {
    const [createOpen, setCreateOpen] = useState(false);
    const [editing, setEditing] = useState<Schedule | null>(null);
    const [deleting, setDeleting] = useState<Schedule | null>(null);
    const { hasPermission } = usePermissions();
    const canCreate = hasPermission('create-schedules');
    const canUpdate = hasPermission('update-schedules');
    const canDelete = hasPermission('delete-schedules');

    function handleDelete() {
        if (!deleting) {
            return;
        }

        router.delete(destroy(deleting.id), {
            onSuccess: () => setDeleting(null),
        });
    }

    const grouped = new Map<string, Schedule[]>();

    for (const schedule of schedules) {
        const key = schedule.day_of_week ?? UNSCHEDULED;
        grouped.set(key, [...(grouped.get(key) ?? []), schedule]);
    }

    const columns = BOARD_COLUMNS.filter(
        (day) =>
            day !== UNSCHEDULED || (grouped.get(UNSCHEDULED)?.length ?? 0) > 0,
    );

    return (
        <>
            <Head title="Jadwal" />

            <div className="flex h-full flex-1 flex-col gap-6 p-4 md:p-6">
                <PageHeader
                    title="Jadwal"
                    actions={
                        canCreate && (
                            <Button asChild>
                                <button
                                    type="button"
                                    onClick={() => setCreateOpen(true)}
                                >
                                    <Plus className="h-4 w-4" />
                                    Tambah
                                </button>
                            </Button>
                        )
                    }
                />

                <p className="hidden text-xs text-muted-foreground md:block">
                    Geser ke samping untuk melihat hari lainnya.
                </p>

                <CreateForm
                    open={createOpen}
                    onOpenChange={setCreateOpen}
                    courseClasses={courseClasses}
                />

                <EditForm
                    key={editing?.id}
                    open={editing !== null}
                    onOpenChange={(open) => {
                        if (!open) {
                            setEditing(null);
                        }
                    }}
                    editing={editing}
                    courseClasses={courseClasses}
                />

                {schedules.length === 0 ? (
                    <p className="text-sm text-muted-foreground">
                        Belum ada data jadwal.
                    </p>
                ) : (
                    <div className="flex flex-1 flex-col gap-4 pb-2 md:flex-row md:overflow-x-auto">
                        {columns.map((day) => {
                            const items = grouped.get(day) ?? [];

                            return (
                                <div
                                    key={day}
                                    className="flex w-full shrink-0 flex-col gap-3 border-b pb-6 last:border-b-0 last:pb-0 md:w-72 md:border-b-0 md:pb-0"
                                >
                                    <div className="flex items-center justify-between rounded-md bg-muted px-3 py-2">
                                        <span className="text-sm font-semibold">
                                            {day === UNSCHEDULED
                                                ? 'Belum Diatur'
                                                : DayOfWeekLabels[day]}
                                        </span>
                                        <Badge variant="secondary">
                                            {items.length}
                                        </Badge>
                                    </div>

                                    <div className="flex flex-col gap-3">
                                        {items.length === 0 ? (
                                            <p className="rounded-md border border-dashed p-4 text-center text-xs text-muted-foreground">
                                                Tidak ada jadwal
                                            </p>
                                        ) : (
                                            items.map((schedule) => (
                                                <Card
                                                    key={schedule.id}
                                                    className={cn(
                                                        'gap-3 py-4',
                                                        highlight ===
                                                        schedule.id &&
                                                        'ring-2 ring-primary',
                                                    )}
                                                >
                                                    <CardHeader className="flex flex-row items-start justify-between gap-2 px-4">
                                                        <CardTitle className="text-sm leading-tight">
                                                            {courseClassLabel(
                                                                schedule.course_class ?? {
                                                                    id: 0,
                                                                    course: null,
                                                                },
                                                            )}
                                                        </CardTitle>
                                                        <RowActions
                                                            wrapperClassName="-mt-1 -mr-2 flex items-center gap-1"
                                                            actions={[
                                                                {
                                                                    label: 'Edit',
                                                                    icon: (
                                                                        <Pencil className="h-3.5 w-3.5" />
                                                                    ),
                                                                    show: canUpdate,
                                                                    onClick:
                                                                        () =>
                                                                            setEditing(
                                                                                schedule,
                                                                            ),
                                                                },
                                                                {
                                                                    label: 'Hapus',
                                                                    icon: (
                                                                        <Trash2 className="h-3.5 w-3.5 text-destructive" />
                                                                    ),
                                                                    show: canDelete,
                                                                    onClick:
                                                                        () =>
                                                                            setDeleting(
                                                                                schedule,
                                                                            ),
                                                                },
                                                            ]}
                                                        />
                                                    </CardHeader>
                                                    <CardContent className="flex flex-col gap-1.5 px-4 text-xs text-muted-foreground">
                                                        {(schedule.start_time ||
                                                            schedule.end_time) && (
                                                                <span className="inline-flex items-center gap-1.5">
                                                                    <Clock className="h-3.5 w-3.5 shrink-0" />
                                                                    {toTimeInput(
                                                                        schedule.start_time,
                                                                    ) || '-'}{' '}
                                                                    -{' '}
                                                                    {toTimeInput(
                                                                        schedule.end_time,
                                                                    ) || '-'}
                                                                </span>
                                                            )}
                                                        {schedule.room && (
                                                            <span className="inline-flex items-center gap-1.5">
                                                                <MapPin className="h-3.5 w-3.5 shrink-0" />
                                                                {schedule.room}
                                                            </span>
                                                        )}
                                                        {schedule.online_link && (
                                                            <a
                                                                href={
                                                                    schedule.online_link
                                                                }
                                                                target="_blank"
                                                                rel="noreferrer"
                                                                className="inline-flex items-center gap-1.5 text-primary underline underline-offset-4 hover:text-primary/80"
                                                            >
                                                                <Video className="h-3.5 w-3.5 shrink-0" />
                                                                Link Online
                                                            </a>
                                                        )}
                                                    </CardContent>
                                                </Card>
                                            ))
                                        )}
                                    </div>
                                </div>
                            );
                        })}
                    </div>
                )}

                <DeleteConfirmDialog
                    target={deleting}
                    onOpenChange={(open) => {
                        if (!open) {
                            setDeleting(null);
                        }
                    }}
                    title="Hapus Jadwal"
                    description={(schedule) =>
                        `Apakah Anda yakin ingin menghapus jadwal "${schedule.course_class?.course?.name ?? 'ini'}"? Tindakan ini tidak dapat dibatalkan.`
                    }
                    onConfirm={handleDelete}
                />
            </div>
        </>
    );
}

function CreateForm({
    open,
    onOpenChange,
    courseClasses,
}: {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    courseClasses: CourseClassOption[];
}) {
    return (
        <FormDialog
            open={open}
            onOpenChange={onOpenChange}
            title="Tambah Jadwal"
            action={store()}
            resetOnSuccess
            onSuccess={() => onOpenChange(false)}
        >
            {({ errors }) => (
                <div className="grid gap-4">
                    <div className="grid gap-2">
                        <Label>
                            Kelas <span className="text-destructive">*</span>
                        </Label>
                        <input type="hidden" name="course_class_id" />
                        <Select name="course_class_id">
                            <SelectTrigger className="w-full">
                                <SelectValue placeholder="Pilih kelas" />
                            </SelectTrigger>
                            <SelectContent>
                                {courseClasses.map((courseClass) => (
                                    <SelectItem
                                        key={courseClass.id}
                                        value={String(courseClass.id)}
                                    >
                                        {courseClassLabel(courseClass)}
                                    </SelectItem>
                                ))}
                            </SelectContent>
                        </Select>
                        <InputError message={errors.course_class_id} />
                    </div>
                    <div className="grid gap-2">
                        <Label>Hari</Label>
                        <input type="hidden" name="day_of_week" />
                        <Select name="day_of_week">
                            <SelectTrigger className="w-full">
                                <SelectValue placeholder="Pilih hari" />
                            </SelectTrigger>
                            <SelectContent>
                                {DaysOfWeek.map((day) => (
                                    <SelectItem key={day} value={day}>
                                        {DayOfWeekLabels[day]}
                                    </SelectItem>
                                ))}
                            </SelectContent>
                        </Select>
                        <InputError message={errors.day_of_week} />
                    </div>
                    <div className="grid grid-cols-2 gap-4">
                        <div className="grid gap-2">
                            <Label htmlFor="start_time">Jam Mulai</Label>
                            <Input
                                id="start_time"
                                name="start_time"
                                type="time"
                            />
                            <InputError message={errors.start_time} />
                        </div>
                        <div className="grid gap-2">
                            <Label htmlFor="end_time">Jam Selesai</Label>
                            <Input id="end_time" name="end_time" type="time" />
                            <InputError message={errors.end_time} />
                        </div>
                    </div>
                    <div className="grid gap-2">
                        <Label htmlFor="room">Ruang</Label>
                        <Input
                            id="room"
                            name="room"
                            placeholder="Contoh: R.301"
                        />
                        <InputError message={errors.room} />
                    </div>
                    <div className="grid gap-2">
                        <Label htmlFor="online_link">Link Online</Label>
                        <Input
                            id="online_link"
                            name="online_link"
                            placeholder="https://meet.google.com/xxx-xxxx"
                        />
                        <InputError message={errors.online_link} />
                    </div>
                </div>
            )}
        </FormDialog>
    );
}

function EditForm({
    open,
    onOpenChange,
    editing,
    courseClasses,
}: {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    editing: Schedule | null;
    courseClasses: CourseClassOption[];
}) {
    return (
        <FormDialog
            open={open}
            onOpenChange={onOpenChange}
            title="Edit Jadwal"
            action={editing ? update(editing.id) : ''}
            resetOnSuccess
            onSuccess={() => onOpenChange(false)}
        >
            {({ errors }) =>
                editing && (
                    <div className="grid gap-4">
                        <div className="grid gap-2">
                            <Label>
                                Kelas{' '}
                                <span className="text-destructive">*</span>
                            </Label>
                            <Select
                                name="course_class_id"
                                defaultValue={String(editing.course_class_id)}
                            >
                                <SelectTrigger className="w-full">
                                    <SelectValue placeholder="Pilih kelas" />
                                </SelectTrigger>
                                <SelectContent>
                                    {courseClasses.map((courseClass) => (
                                        <SelectItem
                                            key={courseClass.id}
                                            value={String(courseClass.id)}
                                        >
                                            {courseClassLabel(courseClass)}
                                        </SelectItem>
                                    ))}
                                </SelectContent>
                            </Select>
                            <InputError message={errors.course_class_id} />
                        </div>
                        <div className="grid gap-2">
                            <Label>Hari</Label>
                            <Select
                                name="day_of_week"
                                defaultValue={editing.day_of_week ?? undefined}
                            >
                                <SelectTrigger className="w-full">
                                    <SelectValue placeholder="Pilih hari" />
                                </SelectTrigger>
                                <SelectContent>
                                    {DaysOfWeek.map((day) => (
                                        <SelectItem key={day} value={day}>
                                            {DayOfWeekLabels[day]}
                                        </SelectItem>
                                    ))}
                                </SelectContent>
                            </Select>
                            <InputError message={errors.day_of_week} />
                        </div>
                        <div className="grid grid-cols-2 gap-4">
                            <div className="grid gap-2">
                                <Label htmlFor="edit-start_time">
                                    Jam Mulai
                                </Label>
                                <Input
                                    id="edit-start_time"
                                    name="start_time"
                                    type="time"
                                    defaultValue={toTimeInput(
                                        editing.start_time,
                                    )}
                                />
                                <InputError message={errors.start_time} />
                            </div>
                            <div className="grid gap-2">
                                <Label htmlFor="edit-end_time">
                                    Jam Selesai
                                </Label>
                                <Input
                                    id="edit-end_time"
                                    name="end_time"
                                    type="time"
                                    defaultValue={toTimeInput(editing.end_time)}
                                />
                                <InputError message={errors.end_time} />
                            </div>
                        </div>
                        <div className="grid gap-2">
                            <Label htmlFor="edit-room">Ruang</Label>
                            <Input
                                id="edit-room"
                                name="room"
                                placeholder="Contoh: R.301"
                                defaultValue={editing.room ?? ''}
                            />
                            <InputError message={errors.room} />
                        </div>
                        <div className="grid gap-2">
                            <Label htmlFor="edit-online_link">
                                Link Online
                            </Label>
                            <Input
                                id="edit-online_link"
                                name="online_link"
                                placeholder="https://meet.google.com/xxx-xxxx"
                                defaultValue={editing.online_link ?? ''}
                            />
                            <InputError message={errors.online_link} />
                        </div>
                    </div>
                )
            }
        </FormDialog>
    );
}
