import { router } from '@inertiajs/react';
import { AlertCircleIcon, SparklesIcon, TrashIcon } from 'lucide-react';
import { type ReactNode, useState } from 'react';
import {
    formatMinutes,
    toDatetimeLocalValue,
} from '@/components/classrooms/format';
import type {
    AiPlannedMeeting,
    AiSchedule,
} from '@/components/classrooms/types';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { Button } from '@/components/ui/button';
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogFooter,
    DialogHeader,
    DialogTitle,
    DialogTrigger,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Spinner } from '@/components/ui/spinner';
import {
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableHeader,
    TableRow,
} from '@/components/ui/table';
import { postJson, rowErrorMessages } from '@/lib/ai';
import classrooms from '@/routes/classrooms';

const EXAMPLES = [
    '5 lezioni di 4 ore, martedì e giovedì dalle 9, dal 1 ottobre 2026',
    '3 lezioni di 2 ore, lunedì e mercoledì dalle 9, dal 6 ottobre 2026',
    '8 incontri di 3 ore, venerdì dalle 14:30, dal 9 ottobre 2026',
];

type Props = {
    classroomUuid: string;
    remainingMinutes: number;
    trigger: ReactNode;
};

export default function SchedulePlannerDialog({
    classroomUuid,
    remainingMinutes,
    trigger,
}: Props) {
    const [open, setOpen] = useState(false);
    const [prompt, setPrompt] = useState('');
    const [meetings, setMeetings] = useState<AiPlannedMeeting[] | null>(null);
    const [warnings, setWarnings] = useState<string[]>([]);
    const [error, setError] = useState<string | null>(null);
    const [planning, setPlanning] = useState(false);
    const [creating, setCreating] = useState(false);
    const [createErrors, setCreateErrors] = useState<string[]>([]);

    function handleOpenChange(next: boolean) {
        setOpen(next);
        if (!next) {
            setPrompt('');
            setMeetings(null);
            setWarnings([]);
            setError(null);
            setPlanning(false);
            setCreating(false);
            setCreateErrors([]);
        }
    }

    async function plan() {
        setPlanning(true);
        setError(null);

        try {
            const data = await postJson<AiSchedule>(
                classrooms.meetings.aiPlan({ classroom: classroomUuid }).url,
                { prompt },
            );

            setMeetings(data.meetings);
            setWarnings(data.warnings);
        } catch (e) {
            setError(e instanceof Error ? e.message : 'Errore imprevisto.');
        } finally {
            setPlanning(false);
        }
    }

    function updateMeeting(
        index: number,
        patch: Partial<AiPlannedMeeting>,
    ): void {
        setMeetings((current) =>
            (current ?? []).map((meeting, i) =>
                i === index ? { ...meeting, ...patch } : meeting,
            ),
        );
    }

    function create() {
        if (!meetings || meetings.length === 0) {
            return;
        }

        setCreating(true);
        setCreateErrors([]);

        router.post(
            classrooms.meetings.bulk({ classroom: classroomUuid }).url,
            { meetings },
            {
                preserveScroll: true,
                onSuccess: () => handleOpenChange(false),
                onError: (errors) =>
                    setCreateErrors(rowErrorMessages(errors, 'meetings')),
                onFinish: () => setCreating(false),
            },
        );
    }

    const plannedMinutes = (meetings ?? []).reduce(
        (total, meeting) => total + meeting.duration_minutes,
        0,
    );

    return (
        <Dialog open={open} onOpenChange={handleOpenChange}>
            <DialogTrigger asChild>{trigger}</DialogTrigger>
            <DialogContent className="max-h-[90vh] gap-0 overflow-y-auto sm:max-w-3xl">
                <DialogHeader>
                    <DialogTitle>Genera calendario</DialogTitle>
                    <DialogDescription>
                        Descrivi il calendario in una frase e controlla le
                        lezioni proposte prima di crearle. Ore ancora
                        disponibili: {formatMinutes(remainingMinutes)}.
                    </DialogDescription>
                </DialogHeader>

                <div className="space-y-4 py-4">
                    {meetings === null ? (
                        <div className="grid gap-2">
                            <Label htmlFor="ai-schedule-prompt">
                                Come vuoi organizzare le lezioni?
                            </Label>
                            <Input
                                id="ai-schedule-prompt"
                                value={prompt}
                                maxLength={500}
                                placeholder={EXAMPLES[0]}
                                onChange={(e) => setPrompt(e.target.value)}
                                onKeyDown={(e) => {
                                    if (e.key === 'Enter' && prompt.trim()) {
                                        e.preventDefault();
                                        void plan();
                                    }
                                }}
                            />
                            <div className="space-y-1 pt-1">
                                <p className="text-muted-foreground text-xs">
                                    Per esempio:
                                </p>
                                {EXAMPLES.map((example) => (
                                    <button
                                        key={example}
                                        type="button"
                                        onClick={() => setPrompt(example)}
                                        className="text-muted-foreground hover:text-foreground block text-left text-xs underline underline-offset-4"
                                    >
                                        {example}
                                    </button>
                                ))}
                            </div>
                        </div>
                    ) : (
                        <PlannedMeetingsTable
                            meetings={meetings}
                            onChange={updateMeeting}
                            onRemove={(index) =>
                                setMeetings((current) =>
                                    (current ?? []).filter(
                                        (_, i) => i !== index,
                                    ),
                                )
                            }
                        />
                    )}

                    {warnings.length > 0 && (
                        <Alert>
                            <AlertCircleIcon />
                            <AlertTitle>Da controllare</AlertTitle>
                            <AlertDescription>
                                {warnings.map((warning) => (
                                    <p key={warning}>{warning}</p>
                                ))}
                            </AlertDescription>
                        </Alert>
                    )}

                    {createErrors.length > 0 && (
                        <Alert variant="destructive">
                            <AlertCircleIcon />
                            <AlertTitle>
                                Correggi il calendario prima di crearlo
                            </AlertTitle>
                            <AlertDescription>
                                {createErrors.map((message) => (
                                    <p key={message}>{message}</p>
                                ))}
                            </AlertDescription>
                        </Alert>
                    )}

                    {error && (
                        <Alert variant="destructive">
                            <AlertCircleIcon />
                            <AlertTitle>
                                Non è stato possibile generare il calendario
                            </AlertTitle>
                            <AlertDescription>{error}</AlertDescription>
                        </Alert>
                    )}
                </div>

                <DialogFooter>
                    {meetings !== null && (
                        <Button
                            type="button"
                            variant="ghost"
                            onClick={() => setMeetings(null)}
                        >
                            Cambia la richiesta
                        </Button>
                    )}

                    {meetings === null ? (
                        <Button
                            type="button"
                            onClick={plan}
                            disabled={planning || prompt.trim().length === 0}
                        >
                            {planning ? <Spinner /> : <SparklesIcon />}
                            Genera
                        </Button>
                    ) : (
                        <Button
                            type="button"
                            onClick={create}
                            disabled={
                                creating ||
                                meetings.length === 0 ||
                                plannedMinutes > remainingMinutes
                            }
                        >
                            {creating && <Spinner />}
                            {meetings.length === 1
                                ? 'Crea 1 lezione'
                                : `Crea ${meetings.length} lezioni`}
                        </Button>
                    )}
                </DialogFooter>
            </DialogContent>
        </Dialog>
    );
}

function PlannedMeetingsTable({
    meetings,
    onChange,
    onRemove,
}: {
    meetings: AiPlannedMeeting[];
    onChange: (index: number, patch: Partial<AiPlannedMeeting>) => void;
    onRemove: (index: number) => void;
}) {
    if (meetings.length === 0) {
        return (
            <p className="text-muted-foreground py-6 text-center text-sm">
                Nessuna lezione da creare.
            </p>
        );
    }

    return (
        <div className="rounded-xl border">
            <Table>
                <TableHeader>
                    <TableRow>
                        <TableHead className="w-[38%]">Titolo</TableHead>
                        <TableHead className="w-[32%]">Data e ora</TableHead>
                        <TableHead className="w-[22%]">
                            Durata (minuti)
                        </TableHead>
                        <TableHead className="w-[8%]" />
                    </TableRow>
                </TableHeader>
                <TableBody>
                    {meetings.map((meeting, index) => (
                        <TableRow key={index}>
                            <TableCell>
                                <Input
                                    aria-label={`Titolo lezione ${index + 1}`}
                                    value={meeting.title}
                                    onChange={(e) =>
                                        onChange(index, {
                                            title: e.target.value,
                                        })
                                    }
                                />
                            </TableCell>
                            <TableCell>
                                <Input
                                    aria-label={`Data e ora lezione ${index + 1}`}
                                    type="datetime-local"
                                    value={toDatetimeLocalValue(
                                        meeting.scheduled_at,
                                    )}
                                    onChange={(e) =>
                                        onChange(index, {
                                            scheduled_at: e.target.value,
                                        })
                                    }
                                />
                            </TableCell>
                            <TableCell>
                                <Input
                                    aria-label={`Durata lezione ${index + 1}`}
                                    type="number"
                                    min={15}
                                    max={720}
                                    step={15}
                                    value={meeting.duration_minutes}
                                    onChange={(e) =>
                                        onChange(index, {
                                            duration_minutes: Number(
                                                e.target.value,
                                            ),
                                        })
                                    }
                                />
                            </TableCell>
                            <TableCell>
                                <Button
                                    type="button"
                                    variant="ghost"
                                    size="icon"
                                    aria-label={`Rimuovi lezione ${index + 1}`}
                                    onClick={() => onRemove(index)}
                                >
                                    <TrashIcon />
                                </Button>
                            </TableCell>
                        </TableRow>
                    ))}
                </TableBody>
            </Table>
        </div>
    );
}
