import { useEffect, useRef, useState } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { format } from "date-fns";
import { apiRequest } from "@/lib/queryClient";
import { APPOINTMENT_TYPES } from "@/utils/appointmentTypeUtils";
import { Button } from "@/components/ui/button";
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Clock } from "lucide-react";
import { useQuery } from "@tanstack/react-query";
import { useAuth } from "@/hooks/use-auth";
import { useDebounce } from "use-debounce";
import {
  Appointment,
  InsertAppointment,
  insertAppointmentSchema,
  Patient,
  Staff,
  UpdateAppointment,
} from "@repo/db/types";
import { DateInputField } from "@/components/ui/dateInputField";
import { formatLocalDate, parseLocalDate } from "@/utils/dateUtils";
import { toast } from "@/hooks/use-toast";

export interface NewAppointmentPrefill {
  staffId: number;
  date: string;
  startTime: string;
  endTime: string;
  patientId?: number;
  type?: string;
}

interface AppointmentFormProps {
  appointment?: Appointment;
  prefillData?: NewAppointmentPrefill | null;
  onSubmit: (data: InsertAppointment | UpdateAppointment) => void;
  onDelete?: (id: number) => void;
  onOpenChange?: (open: boolean) => void;
  isLoading?: boolean;
}

export function AppointmentForm({
  appointment,
  prefillData,
  onSubmit,
  onDelete,
  onOpenChange,
  isLoading = false,
}: AppointmentFormProps) {
  const { user } = useAuth();
  const inputRef = useRef<HTMLInputElement>(null);
  const [prefillPatient, setPrefillPatient] = useState<Patient | null>(null);
  const [otherTypeDesc, setOtherTypeDesc] = useState<string>(() => {
    const t = appointment?.type ?? "";
    return t.startsWith("other:") ? t.slice(6) : "";
  });
  // Track whether the user explicitly changed the type during this edit session.
  // Used to set typeLocked so the auto-sync won't overwrite a deliberate choice.
  const originalType = useRef<string>(appointment?.type ?? "");
  const [typeChangedByUser, setTypeChangedByUser] = useState(false);

  useEffect(() => {
    const timeout = setTimeout(() => {
      inputRef.current?.focus();
    }, 50); // small delay ensures content is mounted

    return () => clearTimeout(timeout);
  }, []);

  const { data: staffMembersRaw = [] as Staff[] } = useQuery<Staff[]>({
    queryKey: ["/api/staffs/"],
    queryFn: async () => {
      const res = await apiRequest("GET", "/api/staffs/");
      return res.json();
    },
    enabled: !!user,
  });

  const colorMap: Record<string, string> = {
    "Dr. Kai Gao": "bg-blue-600",
    "Dr. Jane Smith": "bg-emerald-600",
  };

  const staffMembers = staffMembersRaw.map((staff) => ({
    ...staff,
    color: colorMap[staff.name] || "bg-gray-400",
  }));

  // Format the date and times for the form
  const defaultValues: Partial<Appointment> = appointment
    ? {
        userId: user?.id,
        patientId: appointment.patientId,
        title: appointment.title,
        date: parseLocalDate(appointment.date),
        startTime: appointment.startTime || "09:00",
        endTime: appointment.endTime || "09:30",
        type: appointment.type?.startsWith("other:") ? "other" : appointment.type,
        notes: appointment.notes || "",
        status: appointment.status || "scheduled",
        staffId:
          typeof appointment.staffId === "number"
            ? appointment.staffId
            : undefined,
      }
    : prefillData
      ? {
          userId: user?.id,
          patientId: prefillData.patientId,
          date: prefillData.date ? parseLocalDate(prefillData.date) : new Date(),
          title: "",
          startTime: prefillData.startTime,
          endTime: prefillData.endTime,
          type: prefillData.type || "checkup",
          status: "scheduled",
          notes: "",
          staffId: prefillData.staffId,
        }
      : {
          userId: user?.id ?? 0,
          date: new Date(),
          title: "",
          startTime: "09:00",
          endTime: "09:30",
          type: "checkup",
          status: "scheduled",
          staffId: staffMembers?.[0]?.id ?? undefined,
        };

  const form = useForm<InsertAppointment>({
    resolver: zodResolver(insertAppointmentSchema),
    defaultValues,
  });

  // -----------------------------
  // PATIENT SEARCH (simple inline search)
  // -----------------------------
  const [selectOpen, setSelectOpen] = useState(false);
  const [patientSearchTerm, setPatientSearchTerm] = useState("");
  const [debouncedPatientSearch] = useDebounce(patientSearchTerm, 300);

  const searchKeyPart = debouncedPatientSearch.trim() || "recent";

  const queryFn = async (): Promise<Patient[]> => {
    const trimmed = debouncedPatientSearch.trim();
    const url = trimmed
      ? `/api/patients/search?name=${encodeURIComponent(trimmed)}&limit=50&offset=0`
      : `/api/patients/recent?limit=50&offset=0`;

    const res = await apiRequest("GET", url);
    if (!res.ok) {
      const err = await res.json().catch(() => ({ message: "Failed to fetch patients" }));
      throw new Error(err.message || "Failed to fetch patients");
    }
    const payload = await res.json();
    return Array.isArray(payload) ? payload : (payload.patients ?? []);
  };

  const {
    data: patients = [],
    isFetching: isFetchingPatients,
    refetch: refetchPatients,
  } = useQuery<Patient[], Error>({
    queryKey: ["patients-dropdown", searchKeyPart],
    queryFn,
    enabled: selectOpen || debouncedPatientSearch.trim().length > 0,
  });

  useEffect(() => {
    if (selectOpen && patients.length === 0) {
      refetchPatients();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [selectOpen]);

  // Prefill form from prefillData prop (new appointment slot click)
  useEffect(() => {
    if (!prefillData) return;
    form.setValue("staffId", prefillData.staffId);
    form.setValue("startTime", prefillData.startTime);
    form.setValue("endTime", prefillData.endTime);
    form.setValue("date", parseLocalDate(prefillData.date));
    if (prefillData.type) form.setValue("type", prefillData.type);
    if (prefillData.patientId) {
      form.setValue("patientId", prefillData.patientId);
      (async () => {
        try {
          const res = await apiRequest("GET", `/api/patients/${prefillData.patientId}`);
          if (res.ok) setPrefillPatient(await res.json());
        } catch {}
      })();
    }
  }, [prefillData]);

  // When editing an appointment, ensure we prefill the patient so SelectValue can render
  useEffect(() => {
    if (!appointment?.patientId) return;

    const pid = Number(appointment.patientId);
    if (Number.isNaN(pid)) return;

    // set form value immediately so the select has a value
    form.setValue("patientId", pid);

    // fetch the single patient record and set prefill
    (async () => {
      try {
        const res = await apiRequest("GET", `/api/patients/${pid}`);
        if (res.ok) {
          const patientRecord = await res.json();
          setPrefillPatient(patientRecord);
        } else {
          let msg = `Failed to load patient (status ${res.status})`;
          try {
            const body = await res.json().catch(() => null);
            if (body && body.message) msg = body.message;
          } catch {}
          toast({
            title: "Could not load patient",
            description: msg,
            variant: "destructive",
          });
        }
      } catch (err) {
        toast({
          title: "Error fetching patient",
          description:
            (err as Error)?.message ||
            "An unknown error occurred while fetching patient details.",
          variant: "destructive",
        });
      }
    })();
    // note: we intentionally do NOT remove prefillPatientd here; it will be cleared when dropdown opens and main list contains the patient
  }, [appointment?.patientId]);

  const handleSubmit = (data: InsertAppointment) => {
    // Make sure patientId is a number
    const patientId =
      typeof data.patientId === "string"
        ? parseInt(data.patientId, 10)
        : data.patientId;

    // Auto-create title if it's empty
    let title = data.title;
    if (!title || title.trim() === "") {
      // Format: "April 19" - just the date
      title = format(data.date, "MMMM d");
    }

    const notes = data.notes || "";

    const selectedStaff =
      staffMembers.find((staff) => staff.id?.toString() === data.staffId) ||
      staffMembers[0];

    if (!selectedStaff) {
      console.error("No staff selected and no available staff in the list");
      return;
    }

    const formattedDate = formatLocalDate(data.date);

    const resolvedType =
      data.type === "other" && otherTypeDesc.trim()
        ? `other:${otherTypeDesc.trim()}`
        : data.type;

    onSubmit({
      ...data,
      userId: Number(user?.id),
      title,
      notes,
      patientId,
      date: formattedDate,
      startTime: data.startTime,
      endTime: data.endTime,
      type: resolvedType,
      // Lock the type when the user has explicitly changed it on an existing appointment
      ...(appointment && typeChangedByUser ? { typeLocked: true } : {}),
    });
  };

  return (
    <div className="form-container">
      <Form {...form}>
        <form
          onSubmit={form.handleSubmit(
            (data) => {
              handleSubmit(data);
            },
            (errors) => {
              console.error("Validation failed:", errors);
            }
          )}
          className="space-y-6"
        >
          <FormField
            control={form.control}
            name="patientId"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Patient</FormLabel>

                <Select
                  disabled={isLoading}
                  onOpenChange={(open: boolean) => {
                    setSelectOpen(open);
                    if (!open) {
                      setPatientSearchTerm("");
                      if (
                        prefillPatient &&
                        patients &&
                        patients.some(
                          (p) => Number(p.id) === Number(prefillPatient.id)
                        )
                      ) {
                        setPrefillPatient(null);
                      }
                    } else {
                      if (!patients || patients.length === 0) refetchPatients();
                    }
                  }}
                  value={
                    field.value == null || // null or undefined
                    (typeof field.value === "number" &&
                      !Number.isFinite(field.value)) || // NaN/Infinity
                    (typeof field.value === "string" &&
                      field.value.trim() === "") || // empty string
                    field.value === "NaN" // defensive check
                      ? ""
                      : String(field.value)
                  }
                  onValueChange={(val) =>
                    field.onChange(val === "" ? undefined : Number(val))
                  }
                >
                  <FormControl>
                    <SelectTrigger>
                      <SelectValue placeholder="Select a patient" />
                    </SelectTrigger>
                  </FormControl>

                  <SelectContent>
                    <div className="p-2" onKeyDown={(e) => e.stopPropagation()}>
                      <Input
                        placeholder="Search by name..."
                        value={patientSearchTerm}
                        onChange={(e) => setPatientSearchTerm(e.target.value)}
                        onClick={(e) => e.stopPropagation()}
                      />
                    </div>

                    {/* Prefill patient only if main list does not already include them */}
                    {prefillPatient &&
                      !patients.some(
                        (p) => Number(p.id) === Number(prefillPatient.id)
                      ) && (
                        <SelectItem
                          key={`prefill-${prefillPatient.id}`}
                          value={prefillPatient.id?.toString() ?? ""}
                        >
                          <div className="flex flex-col items-start">
                            <span className="font-medium">
                              {prefillPatient.firstName}{" "}
                              {prefillPatient.lastName}
                            </span>
                            <span className="text-xs text-muted-foreground">
                              DOB:{" "}
                              {prefillPatient.dateOfBirth
                                ? new Date(
                                    prefillPatient.dateOfBirth
                                  ).toLocaleDateString()
                                : ""}{" "}
                              • {prefillPatient.phone ?? ""}
                            </span>
                          </div>
                        </SelectItem>
                      )}

                    <div className="max-h-60 overflow-y-auto scrollbar-thin scrollbar-thumb-muted-foreground/30">
                      {isFetchingPatients ? (
                        <div className="p-2 text-sm text-muted-foreground">
                          Loading...
                        </div>
                      ) : patients && patients.length > 0 ? (
                        patients.map((patient) => (
                          <SelectItem
                            key={patient.id}
                            value={patient.id?.toString() ?? ""}
                          >
                            <div className="flex flex-col items-start">
                              <span className="font-medium">
                                {patient.firstName} {patient.lastName}
                              </span>
                              <span className="text-xs text-muted-foreground">
                                DOB:{" "}
                                {new Date(
                                  patient.dateOfBirth
                                ).toLocaleDateString()}{" "}
                                • {patient.phone}
                              </span>
                            </div>
                          </SelectItem>
                        ))
                      ) : (
                        <div className="p-2 text-muted-foreground text-sm">
                          No patients found
                        </div>
                      )}
                    </div>
                  </SelectContent>
                </Select>

                <FormMessage />
              </FormItem>
            )}
          />

          <FormField
            control={form.control}
            name="title"
            render={({ field }) => (
              <FormItem>
                <FormLabel>
                  Appointment Title{" "}
                  <span className="text-muted-foreground text-xs">
                    (optional)
                  </span>
                </FormLabel>
                <FormControl>
                  <Input
                    placeholder="Leave blank to auto-fill with date"
                    {...field}
                    disabled={isLoading}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />

          <DateInputField control={form.control} name="date" label="Date" />

          <div className="grid grid-cols-2 gap-4">
            <FormField
              control={form.control}
              name="startTime"
              render={({ field }) => (
                <FormItem>
                  <FormLabel>Start Time</FormLabel>
                  <FormControl>
                    <div className="relative">
                      <Clock className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
                      <Input
                        placeholder="09:00"
                        {...field}
                        disabled={isLoading}
                        className="pl-10"
                        value={
                          typeof field.value === "string" ? field.value : ""
                        }
                      />
                    </div>
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />

            <FormField
              control={form.control}
              name="endTime"
              render={({ field }) => (
                <FormItem>
                  <FormLabel>End Time</FormLabel>
                  <FormControl>
                    <div className="relative">
                      <Clock className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
                      <Input
                        placeholder="09:30"
                        {...field}
                        disabled={isLoading}
                        className="pl-10"
                        value={
                          typeof field.value === "string" ? field.value : ""
                        }
                      />
                    </div>
                  </FormControl>
                  <FormMessage />
                </FormItem>
              )}
            />
          </div>

          <FormField
            control={form.control}
            name="type"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Appointment Type</FormLabel>
                <Select
                  disabled={isLoading}
                  onValueChange={(val) => {
                    field.onChange(val);
                    if (val !== "other") setOtherTypeDesc("");
                    if (val !== originalType.current) setTypeChangedByUser(true);
                  }}
                  value={field.value}
                  defaultValue={field.value}
                >
                  <FormControl>
                    <SelectTrigger>
                      <SelectValue placeholder="Select a type" />
                    </SelectTrigger>
                  </FormControl>
                  <SelectContent>
                    {APPOINTMENT_TYPES.map((t) => (
                      <SelectItem key={t.value} value={t.value}>{t.label}</SelectItem>
                    ))}
                  </SelectContent>
                </Select>
                {field.value === "other" && (
                  <Input
                    className="mt-2"
                    placeholder="Describe the appointment type…"
                    value={otherTypeDesc}
                    onChange={(e) => setOtherTypeDesc(e.target.value)}
                    disabled={isLoading}
                    autoFocus
                  />
                )}
                <FormMessage />
              </FormItem>
            )}
          />

          <FormField
            control={form.control}
            name="status"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Status</FormLabel>
                <Select
                  disabled={isLoading}
                  onValueChange={field.onChange}
                  value={field.value}
                  defaultValue={field.value}
                >
                  <FormControl>
                    <SelectTrigger>
                      <SelectValue placeholder="Select a status" />
                    </SelectTrigger>
                  </FormControl>
                  <SelectContent>
                    <SelectItem value="scheduled">Scheduled</SelectItem>
                    <SelectItem value="confirmed">Confirmed</SelectItem>
                    <SelectItem value="completed">Completed</SelectItem>
                    <SelectItem value="cancelled">Cancelled</SelectItem>
                    <SelectItem value="no-show">No Show</SelectItem>
                  </SelectContent>
                </Select>
                <FormMessage />
              </FormItem>
            )}
          />

          <FormField
            control={form.control}
            name="staffId"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Doctor/Hygienist</FormLabel>
                <Select
                  disabled={isLoading}
                  onValueChange={(val) => field.onChange(Number(val))}
                  value={field.value ? String(field.value) : undefined}
                  defaultValue={field.value ? String(field.value) : undefined}
                >
                  <FormControl>
                    <SelectTrigger>
                      <SelectValue placeholder="Select staff member" />
                    </SelectTrigger>
                  </FormControl>
                  <SelectContent>
                    {staffMembers.map((staff) => (
                      <SelectItem
                        key={staff.id}
                        value={staff.id?.toString() || ""}
                      >
                        {staff.name} ({staff.role})
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
                <FormMessage />
              </FormItem>
            )}
          />

          <FormField
            control={form.control}
            name="notes"
            render={({ field }) => (
              <FormItem>
                <FormLabel>Notes</FormLabel>
                <FormControl>
                  <Textarea
                    placeholder="Enter any notes about the appointment"
                    {...field}
                    disabled={isLoading}
                    className="min-h-24"
                    value={field.value ?? ""}
                  />
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />

          <Button type="submit" disabled={isLoading} className="w-full">
            {appointment ? "Update Appointment" : "Create Appointment"}
          </Button>

          {appointment?.id && onDelete && (
            <Button
              type="button"
              onClick={() => {
                onOpenChange?.(false); // 👈 Close the modal first

                setTimeout(() => {
                  onDelete?.(appointment.id!);
                }, 300); // 300ms is safe for most animations
              }}
              className="bg-red-600 text-white w-full rounded hover:bg-red-700"
            >
              Delete Appointment
            </Button>
          )}
        </form>
      </Form>
    </div>
  );
}
