"use client";

import { addHours, addMinutes, isValid, parseISO } from "date-fns";
import { useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { DateTimePicker } from "@/components/date-time-picker";
import { LocationAutocomplete } from "@/components/location-autocomplete";
import { RecurrencePicker } from "@/components/recurrence-picker";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { cn } from "@/lib/utils";
import {
  Drawer,
  DrawerContent,
  DrawerDescription,
  DrawerFooter,
  DrawerHeader,
  DrawerTitle,
} from "@/components/ui/drawer";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Textarea } from "@/components/ui/textarea";
import { useIsMobile } from "@/hooks/use-mobile";
import {
  type EventFormValues,
  getDefaultEventFormValues,
  validateEventFormValues,
} from "@/lib/event-form";
import { parseRecurrenceRule, validateRecurrence } from "@/lib/recurrence";

interface EventDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  editingId: string | null;
  dialogSource: "manual" | "ai";
  initialValues: EventFormValues;
  onSave: (values: EventFormValues) => void;
  onReset: () => void;
}

export const EventDialog = ({
  open,
  onOpenChange,
  editingId,
  dialogSource,
  initialValues,
  onSave,
  onReset,
}: EventDialogProps) => {
  const isMobile = useIsMobile();
  const isAiDraft = dialogSource === "ai" && !editingId;
  const titleText = editingId ? "Edit Event" : isAiDraft ? "Review AI Draft" : "New Event";
  const descriptionText = editingId
    ? "Update the event details below. Title and start date are required."
    : isAiDraft
      ? "AI filled in this event from your prompt. Review each field, then save when it looks right."
      : "Create an event manually. Title and start date are required.";
  const saveLabel = editingId ? "Update Event" : "Save Event";

  const {
    control,
    handleSubmit,
    register,
    reset,
    setError,
    setValue,
    trigger,
    watch,
    formState: { errors },
  } = useForm<EventFormValues>({
    defaultValues: getDefaultEventFormValues(),
  });

  const [step, setStep] = useState<1 | 2 | 3>(1);
  const advanceStep = () => setStep((s) => Math.min(s + 1, 3) as 1 | 2 | 3);
  const retreatStep = () => setStep((s) => Math.max(s - 1, 1) as 1 | 2 | 3);

  useEffect(() => {
    reset(initialValues);
  }, [initialValues, reset]);

  const handleOpenChange = (nextOpen: boolean) => {
    if (!nextOpen) {
      reset(getDefaultEventFormValues());
      setStep(1);
      onReset();
    }
    onOpenChange(nextOpen);
  };

  const STEP_FIELDS: Record<1 | 2 | 3, (keyof EventFormValues)[]> = {
    1: ["title", "url"],
    2: ["start", "end"],
    3: ["recurrenceRule"],
  };

  const handleNext = async () => {
    const valid = await trigger(STEP_FIELDS[step]);
    if (valid) advanceStep();
  };

  const handleSave = handleSubmit((values) => {
    const result = validateEventFormValues(values);
    if (!result.success) {
      const fieldErrors = result.error.flatten().fieldErrors;
      let firstErrorStep: 1 | 2 | 3 | null = null;
      for (const [fieldName, messages] of Object.entries(fieldErrors)) {
        const firstMessage = messages?.[0];
        if (firstMessage) {
          setError(fieldName as keyof EventFormValues, { message: firstMessage });
          const ownerStep = (
            Object.entries(STEP_FIELDS) as [string, (keyof EventFormValues)[]][]
          ).find(([, fields]) => fields.includes(fieldName as keyof EventFormValues))?.[0];
          const ownerStepNum = ownerStep ? (Number(ownerStep) as 1 | 2 | 3) : null;
          if (ownerStepNum !== null && (firstErrorStep === null || ownerStepNum < firstErrorStep)) {
            firstErrorStep = ownerStepNum;
          }
        }
      }
      if (firstErrorStep !== null) setStep(firstErrorStep);
      return;
    }

    if (values.recurrenceRule) {
      const recurrenceValidation = validateRecurrence(parseRecurrenceRule(values.recurrenceRule));
      if (!recurrenceValidation.isValid) {
        setError("recurrenceRule", {
          message:
            recurrenceValidation.errors.rule ||
            recurrenceValidation.errors.count ||
            recurrenceValidation.errors.until ||
            "Invalid recurrence.",
        });
        setStep(3);
        return;
      }
    }

    onSave(result.data);
    reset(getDefaultEventFormValues());
  });

  const onSubmit = handleSubmit((values) => {
    const result = validateEventFormValues(values);
    if (!result.success) {
      const fieldErrors = result.error.flatten().fieldErrors;
      for (const [fieldName, messages] of Object.entries(fieldErrors)) {
        const firstMessage = messages?.[0];
        if (firstMessage) {
          setError(fieldName as keyof EventFormValues, {
            message: firstMessage,
          });
        }
      }
      return;
    }

    if (values.recurrenceRule) {
      const recurrenceValidation = validateRecurrence(parseRecurrenceRule(values.recurrenceRule));
      if (!recurrenceValidation.isValid) {
        setError("recurrenceRule", {
          message:
            recurrenceValidation.errors.rule ||
            recurrenceValidation.errors.count ||
            recurrenceValidation.errors.until ||
            "Invalid recurrence.",
        });
        return;
      }
    }

    onSave(result.data);
    reset(getDefaultEventFormValues());
  });

  const stepProps = { control, register, errors, watch, setValue, isAiDraft };

  const progressBars = (
    <div className="grid grid-cols-3 gap-1.5 px-4 pt-2 pb-3">
      {([1, 2, 3] as const).map((n) => (
        <div
          key={n}
          className={cn(
            "h-[3px] rounded-full transition-colors duration-200",
            n <= step ? "bg-foreground" : "bg-muted",
          )}
        />
      ))}
    </div>
  );

  const stepTitles: Record<1 | 2 | 3, string> = {
    1: "Event Details",
    2: "Schedule",
    3: "Recurrence",
  };

  if (!isMobile) {
    return (
      <Dialog open={open} onOpenChange={handleOpenChange}>
        <DialogContent className="max-w-2xl rounded-[10px] bg-card p-0 shadow-xl">
          <DialogHeader className="px-6 py-5 shadow-[inset_0_-1px_0_0_var(--color-border)]">
            <DialogTitle className="text-[28px] tracking-[-0.06em]">{titleText}</DialogTitle>
            <DialogDescription>{descriptionText}</DialogDescription>
          </DialogHeader>
          <form className="grid gap-6 px-6 py-5" onSubmit={onSubmit}>
            {isAiDraft && <AiDraftBanner />}
            <section className="grid gap-3">
              <p className="font-mono text-[11px] uppercase text-muted-foreground">Event details</p>
              <DetailsStep {...stepProps} />
            </section>
            <section className="grid gap-3">
              <p className="font-mono text-[11px] uppercase text-muted-foreground">Schedule</p>
              <ScheduleStep {...stepProps} />
            </section>
            <section className="grid gap-3">
              <p className="font-mono text-[11px] uppercase text-muted-foreground">Recurrence</p>
              <RecurrenceStep {...stepProps} />
            </section>
            <DialogFooter>
              <Button type="button" variant="ghost" onClick={() => handleOpenChange(false)}>
                Cancel
              </Button>
              <Button type="submit">{saveLabel}</Button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>
    );
  }

  return (
    <Drawer open={open} onOpenChange={handleOpenChange}>
      <DrawerContent>
        <DrawerHeader>
          <div className="flex items-start justify-between gap-3">
            <div>
              <DrawerTitle>{stepTitles[step]}</DrawerTitle>
              <DrawerDescription className="mt-1">
                {step === 1 && "Title and start date are required."}
                {step === 2 && "Set your event's date and time."}
                {step === 3 && "Optionally repeat this event."}
              </DrawerDescription>
            </div>
            <span className="shrink-0 rounded-full bg-muted px-2.5 py-1 text-xs text-muted-foreground">
              {step} / 3
            </span>
          </div>
        </DrawerHeader>
        {progressBars}
        <form onSubmit={handleSave}>
          <div className="overflow-y-auto px-4 pb-4 max-h-[55dvh]">
            {step === 1 && <DetailsStep {...stepProps} />}
            {step === 2 && <ScheduleStep {...stepProps} />}
            {step === 3 && <RecurrenceStep {...stepProps} />}
          </div>
          <DrawerFooter>
            <Button
              type="button"
              variant="outline"
              onClick={step === 1 ? () => handleOpenChange(false) : retreatStep}
            >
              {step === 1 ? "Cancel" : "Back"}
            </Button>
            {step < 3 ? (
              <Button type="button" onClick={handleNext}>
                Next
              </Button>
            ) : (
              <Button type="submit">{saveLabel}</Button>
            )}
          </DrawerFooter>
        </form>
      </DrawerContent>
    </Drawer>
  );
};

interface StepProps {
  control: ReturnType<typeof useForm<EventFormValues>>["control"];
  register: ReturnType<typeof useForm<EventFormValues>>["register"];
  errors: ReturnType<typeof useForm<EventFormValues>>["formState"]["errors"];
  watch: ReturnType<typeof useForm<EventFormValues>>["watch"];
  setValue: ReturnType<typeof useForm<EventFormValues>>["setValue"];
  isAiDraft: boolean;
}

function AiDraftBanner() {
  return (
    <div className="rounded-md border border-primary/20 bg-primary/5 px-3 py-2 text-xs leading-relaxed text-primary">
      This draft was generated from natural language. Double-check dates, times, location,
      recurrence, and links before saving.
    </div>
  );
}

function DetailsStep({
  control,
  register,
  errors,
  isAiDraft,
}: Omit<StepProps, "watch" | "setValue">) {
  const isMobile = useIsMobile();
  return (
    <div className="grid gap-4">
      {isAiDraft && <AiDraftBanner />}
      <div className="space-y-1.5">
        <Label htmlFor="event-title">Title</Label>
        <Input
          id="event-title"
          placeholder="Event title"
          className="font-medium"
          {...register("title")}
        />
        {errors.title && <p className="text-xs text-destructive">{errors.title.message}</p>}
      </div>
      <div className="space-y-1.5">
        <Label htmlFor="event-description">Description / notes</Label>
        <Textarea
          id="event-description"
          className="field-sizing-content min-h-[60px] max-h-40 resize-none placeholder:text-muted-foreground/50"
          placeholder="Add a description..."
          {...register("description")}
        />
      </div>
      <div className={isMobile ? "grid grid-cols-1 gap-3" : "grid grid-cols-2 gap-3"}>
        <div className="space-y-1.5">
          <Label htmlFor="event-location">Location</Label>
          <Controller
            name="location"
            control={control}
            render={({ field }) => (
              <LocationAutocomplete
                id="event-location"
                onChange={field.onChange}
                value={field.value}
              />
            )}
          />
        </div>
        <div className="space-y-1.5">
          <Label htmlFor="event-url">URL</Label>
          <Input id="event-url" placeholder="URL" {...register("url")} />
          {errors.url && <p className="text-xs text-destructive">{errors.url.message}</p>}
        </div>
      </div>
    </div>
  );
}

function ScheduleStep({
  control,
  errors,
  watch,
  setValue,
  isAiDraft,
}: Omit<StepProps, "register">) {
  const allDay = watch("allDay");
  const start = watch("start");

  const DURATIONS = [
    { label: "+15 min", minutes: 15 },
    { label: "+30 min", minutes: 30 },
    { label: "+1 hour", minutes: 60 },
    { label: "+3 hours", minutes: 180 },
  ];

  const handleApplyDuration = (minutes: number) => {
    if (!start) return;
    const base = parseISO(start);
    if (!isValid(base)) return;
    const next = minutes < 60 ? addMinutes(base, minutes) : addHours(base, minutes / 60);
    const pad = (v: number) => String(v).padStart(2, "0");
    const result = allDay
      ? `${next.getFullYear()}-${pad(next.getMonth() + 1)}-${pad(next.getDate())}`
      : `${next.getFullYear()}-${pad(next.getMonth() + 1)}-${pad(next.getDate())}T${pad(next.getHours())}:${pad(next.getMinutes())}:00`;
    setValue("end", result, { shouldDirty: true });
  };

  return (
    <div className="grid gap-4">
      {isAiDraft && <AiDraftBanner />}
      <div className="flex items-center gap-2 py-1">
        <Controller
          name="allDay"
          control={control}
          render={({ field }) => (
            <Checkbox
              id="event-all-day"
              checked={field.value}
              onCheckedChange={(checked) => field.onChange(checked === true)}
            />
          )}
        />
        <Label htmlFor="event-all-day" className="cursor-pointer text-sm font-normal">
          All day
        </Label>
      </div>
      <div className="space-y-2">
        <Controller
          name="start"
          control={control}
          render={({ field }) => (
            <DateTimePicker
              value={field.value}
              onChange={field.onChange}
              allDay={allDay}
              placeholder="Start date"
            />
          )}
        />
        {!allDay && (
          <div className="flex gap-1 pl-0.5">
            {DURATIONS.map(({ label, minutes }) => (
              <Button
                key={label}
                type="button"
                variant="ghost"
                size="sm"
                disabled={!start}
                onClick={() => handleApplyDuration(minutes)}
                className="px-2 py-1 text-xs text-muted-foreground"
              >
                {label}
              </Button>
            ))}
          </div>
        )}
        <Controller
          name="end"
          control={control}
          render={({ field }) => (
            <DateTimePicker
              value={field.value}
              onChange={field.onChange}
              allDay={allDay}
              placeholder="End date"
            />
          )}
        />
        {errors.start && <p className="text-xs text-destructive">{errors.start.message}</p>}
        {errors.end && <p className="text-xs text-destructive">{errors.end.message}</p>}
      </div>
    </div>
  );
}

function RecurrenceStep({
  control,
  errors,
  watch,
  isAiDraft,
}: Omit<StepProps, "register" | "setValue">) {
  const start = watch("start");
  return (
    <div className="grid gap-4">
      {isAiDraft && <AiDraftBanner />}
      <Controller
        name="recurrenceRule"
        control={control}
        render={({ field }) => (
          <RecurrencePicker value={field.value} onChange={field.onChange} start={start} />
        )}
      />
      {errors.recurrenceRule && (
        <p className="text-xs text-destructive">{errors.recurrenceRule.message}</p>
      )}
    </div>
  );
}
