import { Button } from '@/components/ui/button';
import { DatePicker } from '@/components/ui/date-picker';
import { Field, FieldError, FieldLabel } from '@/components/ui/field';
import { Input } from '@/components/ui/input';
import {
  ResponsiveDialog,
  ResponsiveDialogClose,
  ResponsiveDialogContent,
  ResponsiveDialogDescription,
  ResponsiveDialogFooter,
  ResponsiveDialogHeader,
  ResponsiveDialogTitle,
} from '@/components/ui/responsive-dialog';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { zodResolver } from '@hookform/resolvers/zod';
import { useEffect, useMemo, useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { useBooking } from '../booking-provider';
import {
  fromIsoDateLocal,
  getDayOfWeek,
  minutesToTime,
  timeToMinutes,
  toIsoDateLocal,
} from '../lib/booking-time';

const bookingFormSchema = z.object({
  customerName: z
    .string()
    .trim()
    .min(2, 'Ingresa un nombre válido.')
    .max(120, 'El nombre no puede superar los 120 caracteres.'),
  customerPhone: z
    .string()
    .trim()
    .min(6, 'Ingresa un telefono válido.')
    .max(30, 'El telefono no puede superar los 30 caracteres.'),
});

type BookingForm = z.infer<typeof bookingFormSchema>;

export function BookingCreateDialog() {
  const {
    courts,
    bookings,
    selectedDate,
    selectedSlot,
    isCreateBookingOpen,
    createBookingError,
    isCreatingBooking,
    closeCreateBooking,
    createBooking,
  } = useBooking();

  const [date, setDate] = useState(selectedSlot?.date ?? selectedDate);
  const [sportId, setSportId] = useState(selectedSlot?.sportId ?? 'all');
  const [courtId, setCourtId] = useState(selectedSlot?.courtId ?? '');
  const [startTime, setStartTime] = useState(selectedSlot?.startTime ?? '');

  const {
    register,
    handleSubmit,
    reset,
    formState: { errors, isValid },
  } = useForm<BookingForm>({
    resolver: zodResolver(bookingFormSchema),
    mode: 'onChange',
    defaultValues: {
      customerName: '',
      customerPhone: '',
    },
  });

  useEffect(() => {
    if (!isCreateBookingOpen) return;

    setDate(selectedSlot?.date ?? selectedDate);
    setSportId(selectedSlot?.sportId ?? 'all');
    setCourtId(selectedSlot?.courtId ?? '');
    setStartTime(selectedSlot?.startTime ?? '');
    reset();
  }, [isCreateBookingOpen, reset, selectedDate, selectedSlot]);

  const sports = [...new Map(courts.map((court) => [court.sport.id, court.sport])).values()];
  const filteredCourts = useMemo(() => {
    if (sportId === 'all') return courts;
    return courts.filter((court) => court.sportId === sportId);
  }, [courts, sportId]);
  const selectedCourt = courts.find((court) => court.id === courtId);
  const availableStartTimes = useMemo(() => {
    if (!selectedCourt) return [];

    const times: string[] = [];
    const dayOfWeek = getDayOfWeek(date);
    const dayAvailability = selectedCourt.availability
      .filter((range) => range.dayOfWeek === dayOfWeek)
      .sort((a, b) => timeToMinutes(a.startTime) - timeToMinutes(b.startTime));
    const courtBookings = bookings.filter(
      (booking) =>
        booking.date === date &&
        booking.courtId === selectedCourt.id &&
        booking.status !== 'CANCELLED'
    );

    for (const range of dayAvailability) {
      const start = timeToMinutes(range.startTime);
      const end = timeToMinutes(range.endTime);

      for (
        let minute = start;
        minute + selectedCourt.slotDurationMinutes <= end;
        minute += selectedCourt.slotDurationMinutes
      ) {
        const slotEnd = minute + selectedCourt.slotDurationMinutes;
        const isBooked = courtBookings.some((booking) => {
          const bookingStart = timeToMinutes(booking.startTime);
          const bookingEnd = timeToMinutes(booking.endTime);
          return minute < bookingEnd && slotEnd > bookingStart;
        });

        if (!isBooked) {
          times.push(minutesToTime(minute));
        }
      }
    }

    return times;
  }, [bookings, date, selectedCourt]);

  useEffect(() => {
    if (startTime && !availableStartTimes.includes(startTime)) {
      setStartTime('');
    }
  }, [availableStartTimes, startTime]);

  const onSubmit = async (values: BookingForm) => {
    await createBooking({
      courtId,
      date,
      startTime,
      customerName: values.customerName,
      customerPhone: values.customerPhone,
    });
  };

  return (
    <ResponsiveDialog
      open={isCreateBookingOpen}
      onOpenChange={(open) => !open && closeCreateBooking()}
    >
      <ResponsiveDialogContent
        className="data-[variant=dialog]:max-w-lg"
        onOpenAutoFocus={(event) => event.preventDefault()}
      >
        <ResponsiveDialogHeader>
          <ResponsiveDialogTitle>Nueva reserva</ResponsiveDialogTitle>
          <ResponsiveDialogDescription>
            Crea un turno para atención telefónica o mostrador.
          </ResponsiveDialogDescription>
        </ResponsiveDialogHeader>

        <form id="booking-create-form" className="grid gap-4" onSubmit={handleSubmit(onSubmit)}>
          <div className="grid gap-3 md:grid-cols-2">
            <Field>
              <FieldLabel>Fecha</FieldLabel>
              <DatePicker
                value={fromIsoDateLocal(date)}
                onChange={(nextDate) => {
                  setDate(nextDate ? toIsoDateLocal(nextDate) : selectedDate);
                }}
              />
            </Field>

            <Field>
              <FieldLabel>Deporte</FieldLabel>
              <Select
                value={sportId}
                onValueChange={(value) => {
                  setSportId(value);
                  setCourtId('');
                  setStartTime('');
                }}
              >
                <SelectTrigger>
                  <SelectValue />
                </SelectTrigger>
                <SelectContent>
                  <SelectItem value="all">Todos</SelectItem>
                  {sports.map((sport) => (
                    <SelectItem key={sport.id} value={sport.id}>
                      {sport.name}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </Field>

            <Field>
              <FieldLabel>Cancha</FieldLabel>
              <Select
                value={courtId}
                onValueChange={(value) => {
                  setCourtId(value);
                  setStartTime('');
                }}
              >
                <SelectTrigger>
                  <SelectValue placeholder="Selecciona una cancha" />
                </SelectTrigger>
                <SelectContent>
                  {filteredCourts.map((court) => (
                    <SelectItem key={court.id} value={court.id}>
                      {court.name} · {court.sport.name}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </Field>

            <Field>
              <FieldLabel>Horario</FieldLabel>
              <Select value={startTime} onValueChange={setStartTime}>
                <SelectTrigger>
                  <SelectValue placeholder="Selecciona un horario" />
                </SelectTrigger>
                <SelectContent>
                  {availableStartTimes.map((time) => (
                    <SelectItem key={time} value={time}>
                      {time}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </Field>
          </div>

          <Field data-invalid={Boolean(errors.customerName)}>
            <FieldLabel htmlFor="customerName">Nombre</FieldLabel>
            <Input
              id="customerName"
              placeholder="Ej: Juan Perez"
              aria-invalid={Boolean(errors.customerName)}
              {...register('customerName')}
            />
            <FieldError errors={[errors.customerName]} />
          </Field>

          <Field data-invalid={Boolean(errors.customerPhone)}>
            <FieldLabel htmlFor="customerPhone">Teléfono</FieldLabel>
            <Input
              id="customerPhone"
              type="tel"
              placeholder="Ej: 3875551234"
              aria-invalid={Boolean(errors.customerPhone)}
              {...register('customerPhone')}
            />
            <FieldError errors={[errors.customerPhone]} />
          </Field>

          {createBookingError && <p className="text-sm text-destructive">{createBookingError}</p>}
        </form>

        <ResponsiveDialogFooter>
          <ResponsiveDialogClose asChild>
            <Button variant="outline">Cancelar</Button>
          </ResponsiveDialogClose>
          <Button
            type="submit"
            form="booking-create-form"
            disabled={!isValid || isCreatingBooking || !courtId || !startTime}
          >
            {isCreatingBooking ? 'Guardando...' : 'Crear reserva'}
          </Button>
        </ResponsiveDialogFooter>
      </ResponsiveDialogContent>
    </ResponsiveDialog>
  );
}
