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 { Separator } from '@/components/ui/separator';
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,
  getNowTime,
  isTodayIso,
  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.'),
  customerEmail: z.string().email('Ingresá un email válido.').or(z.literal('')),
});

type BookingForm = z.infer<typeof bookingFormSchema>;

export function BookingCreateDialog() {
  const {
    courts,
    bookings,
    selectedDate,
    selectedSlot,
    isCreateBookingOpen,
    createBookingError,
    isCreatingBooking,
    closeCreateBooking,
    createBooking,
    createRecurringBooking,
    isRecurringEnabled,
  } = 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 [isRecurring, setIsRecurring] = useState(false);
  const [recurringEndDate, setRecurringEndDate] = useState<string | undefined>(undefined);

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

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

    setDate(selectedSlot?.date ?? selectedDate);
    setSportId(selectedSlot?.sportId ?? 'all');
    setCourtId(selectedSlot?.courtId ?? '');
    setStartTime(selectedSlot?.startTime ?? '');
    setIsRecurring(false);
    setRecurringEndDate(undefined);
    reset();

    if (selectedSlot?.courtId && selectedSlot?.startTime) {
      requestAnimationFrame(() => {
        setFocus('customerName');
      });
    }
  }, [isCreateBookingOpen, reset, selectedDate, selectedSlot, setFocus]);

  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;

        if (isTodayIso(date) && minute <= timeToMinutes(getNowTime())) continue;

        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) => {
    if (isRecurring) {
      await createRecurringBooking({
        courtId,
        date,
        startTime,
        customerName: values.customerName,
        customerPhone: values.customerPhone,
        customerEmail: values.customerEmail,
        recurringEndDate,
      });
    } else {
      await createBooking({
        courtId,
        date,
        startTime,
        customerName: values.customerName,
        customerPhone: values.customerPhone,
        customerEmail: values.customerEmail,
      });
    }
  };

  return (
    <ResponsiveDialog
      open={isCreateBookingOpen}
      onOpenChange={(open) => !open && closeCreateBooking()}
    >
      <ResponsiveDialogContent
        className="group/create-booking data-[variant=dialog]:max-w-lg data-[variant=drawer]:!h-[92svh] data-[variant=drawer]:!max-h-[92svh] data-[variant=drawer]:overflow-hidden data-[variant=drawer]:px-0 data-[variant=drawer]:pb-0"
        onOpenAutoFocus={(event) => event.preventDefault()}
      >
        <ResponsiveDialogHeader className="group-data-[variant=drawer]/create-booking:shrink-0 group-data-[variant=drawer]/create-booking:px-4 group-data-[variant=drawer]/create-booking:pb-3">
          <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 group-data-[variant=drawer]/create-booking:min-h-0 group-data-[variant=drawer]/create-booking:flex-1 group-data-[variant=drawer]/create-booking:overflow-y-auto group-data-[variant=drawer]/create-booking:px-4 group-data-[variant=drawer]/create-booking:pb-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>

          {isRecurringEnabled && (
            <>
              <Separator />

              <div className="flex items-center justify-between">
                <div className="space-y-0.5">
                  <p className="text-sm font-medium">Repetir todas las semanas</p>
                  <p className="text-xs text-muted-foreground">
                    {isRecurring
                      ? `Se creará una reserva todos los ${getDayOfWeekLabel(date)} a las ${startTime || '...'}`
                      : 'Crea turnos fijos en el mismo horario'}
                  </p>
                </div>
                <Button
                  type="button"
                  variant={isRecurring ? 'default' : 'outline'}
                  size="sm"
                  onClick={() => setIsRecurring(!isRecurring)}
                  className="shrink-0"
                >
                  {isRecurring ? 'Activado' : 'Desactivado'}
                </Button>
              </div>

              {isRecurring && (
                <Field>
                  <FieldLabel>
                    Repetir hasta{' '}
                    <span className="text-muted-foreground font-normal">(opcional)</span>
                  </FieldLabel>
                  <DatePicker
                    value={fromIsoDateLocal(recurringEndDate ?? '')}
                    onChange={(nextDate) => {
                      setRecurringEndDate(nextDate ? toIsoDateLocal(nextDate) : undefined);
                    }}
                  />
                  <p className="mt-1 text-xs text-muted-foreground">
                    Si no se selecciona una fecha, se repetirá por tiempo indefinido.
                  </p>
                </Field>
              )}
            </>
          )}

          <Separator />

          <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>

          <Field data-invalid={Boolean(errors.customerEmail)}>
            <FieldLabel htmlFor="customerEmail">
              Email <span className="text-muted-foreground font-normal">(opcional)</span>
            </FieldLabel>
            <Input
              id="customerEmail"
              type="email"
              placeholder="Ej: juan@ejemplo.com"
              aria-invalid={Boolean(errors.customerEmail)}
              {...register('customerEmail')}
            />
            <p className="mt-1 text-xs text-muted-foreground">
              Se enviará la confirmación de la reserva por email.
            </p>
            <FieldError errors={[errors.customerEmail]} />
          </Field>

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

        <ResponsiveDialogFooter className="group-data-[variant=drawer]/create-booking:shrink-0 group-data-[variant=drawer]/create-booking:border-t group-data-[variant=drawer]/create-booking:border-border/70 group-data-[variant=drawer]/create-booking:bg-popover/95 group-data-[variant=drawer]/create-booking:px-4 group-data-[variant=drawer]/create-booking:pt-3 group-data-[variant=drawer]/create-booking:pb-[calc(12px+env(safe-area-inset-bottom))]">
          <ResponsiveDialogClose asChild>
            <Button variant="outline">Cancelar</Button>
          </ResponsiveDialogClose>
          <Button
            type="submit"
            form="booking-create-form"
            disabled={!isValid || isCreatingBooking || !courtId || !startTime}
          >
            {isCreatingBooking
              ? isRecurring
                ? 'Creando turnos...'
                : 'Guardando...'
              : isRecurring
                ? 'Crear turno fijo'
                : 'Crear reserva'}
          </Button>
        </ResponsiveDialogFooter>
      </ResponsiveDialogContent>
    </ResponsiveDialog>
  );
}

function getDayOfWeekLabel(dateIso: string): string {
  const labels: Record<string, string> = {
    MONDAY: 'lunes',
    TUESDAY: 'martes',
    WEDNESDAY: 'miércoles',
    THURSDAY: 'jueves',
    FRIDAY: 'viernes',
    SATURDAY: 'sábado',
    SUNDAY: 'domingo',
  };
  return labels[getDayOfWeek(dateIso)] ?? '';
}
