"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { ChevronDown, Clock } from "lucide-react";

type TimePickerProps = {
  error?: string[];
  label: string;
  name: string;
  required?: boolean;
  value?: string;
  onChange?: (value: string) => void;
  selectedDate?: string;
};

const START_HOUR = 9;
const END_HOUR = 18;
const SLOT_STEP_MINUTES = 30;

function pad(value: number) {
  return String(value).padStart(2, "0");
}

function toMinutes(time: string) {
  const [hour = 0, minute = 0] = time.split(":").map(Number);
  return hour * 60 + minute;
}

function getDateKey(date: Date) {
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(
    date.getDate()
  )}`;
}

function getTodayString() {
  return getDateKey(new Date());
}

function parseLocalDate(value?: string) {
  if (!value) return null;

  const [year, month, day] = value.split("-").map(Number);

  if (!year || !month || !day) return null;

  return new Date(year, month - 1, day);
}

function normalizeTimeValue(value?: string) {
  if (!value) return null;

  const match = value.match(/^(\d{1,2}):(\d{2})/);

  if (!match) return null;

  const hour = Number(match[1]);
  const minute = Number(match[2]);

  if (Number.isNaN(hour) || Number.isNaN(minute)) return null;
  if (hour < START_HOUR || hour > END_HOUR) return null;
  if (minute !== 0 && minute !== 30) return null;
  if (hour === END_HOUR && minute > 0) return null;

  return `${pad(hour)}:${pad(minute)}`;
}

function formatTimeLabel(time: string) {
  const [hour = 0, minute = 0] = time.split(":").map(Number);
  const period = hour >= 12 ? "PM" : "AM";
  const displayHour = hour % 12 === 0 ? 12 : hour % 12;

  return `${displayHour}:${pad(minute)} ${period}`;
}

const allTimeSlots = Array.from(
  {
    length: (END_HOUR * 60 - START_HOUR * 60) / SLOT_STEP_MINUTES + 1,
  },
  (_, index) => {
    const totalMinutes = START_HOUR * 60 + index * SLOT_STEP_MINUTES;
    const hour = Math.floor(totalMinutes / 60);
    const minute = totalMinutes % 60;
    const value = `${pad(hour)}:${pad(minute)}`;

    return {
      value,
      label: formatTimeLabel(value),
    };
  }
);

export default function TimePicker({
  error,
  label,
  name,
  required,
  value,
  onChange,
  selectedDate,
}: TimePickerProps) {
  const [open, setOpen] = useState(false);
  const [now, setNow] = useState(() => new Date());
  const containerRef = useRef<HTMLDivElement>(null);

  const availableTimeSlots = useMemo(() => {
    const parsedSelectedDate = parseLocalDate(selectedDate);
    const selectedDateKey = parsedSelectedDate
      ? getDateKey(parsedSelectedDate)
      : getTodayString();

    const isToday = selectedDateKey === getTodayString();

    const currentMinutes = now.getHours() * 60 + now.getMinutes();

    return allTimeSlots.filter((slot) => {
      if (!isToday) return true;

      return toMinutes(slot.value) > currentMinutes;
    });
  }, [selectedDate, now]);

  const [selectedTime, setSelectedTime] = useState(() => {
    const normalizedValue = normalizeTimeValue(value);
    return normalizedValue ?? allTimeSlots[0]?.value ?? "";
  });

  const safeSelectedTime = useMemo(() => {
    if (!availableTimeSlots.length) return "";

    if (selectedTime && availableTimeSlots.some((slot) => slot.value === selectedTime)) {
      return selectedTime;
    }

    return availableTimeSlots[0]?.value ?? "";
  }, [availableTimeSlots, selectedTime]);

  const selectedSlot = allTimeSlots.find(
    (slot) => slot.value === safeSelectedTime
  );

  const displayValue = selectedSlot?.label || "No slots available";

  useEffect(() => {
    const normalizedValue = normalizeTimeValue(value);

    if (normalizedValue && normalizedValue !== selectedTime) {
      setSelectedTime(normalizedValue);
    }
  }, [value, selectedTime]);

  useEffect(() => {
    if (safeSelectedTime !== selectedTime) {
      setSelectedTime(safeSelectedTime);
    }

    if (value !== safeSelectedTime) {
      onChange?.(safeSelectedTime);
    }
  }, [safeSelectedTime, selectedTime, value, onChange]);

  useEffect(() => {
    const timer = window.setInterval(() => {
      setNow(new Date());
    }, 60 * 1000);

    return () => {
      window.clearInterval(timer);
    };
  }, []);

  useEffect(() => {
    function handleClickOutside(event: MouseEvent) {
      if (!containerRef.current?.contains(event.target as Node)) {
        setOpen(false);
      }
    }

    function handleEscape(event: KeyboardEvent) {
      if (event.key === "Escape") setOpen(false);
    }

    if (open) {
      document.addEventListener("mousedown", handleClickOutside);
      document.addEventListener("keydown", handleEscape);
    }

    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
      document.removeEventListener("keydown", handleEscape);
    };
  }, [open]);

  const handleTimeSelect = (time: string) => {
    setSelectedTime(time);
    onChange?.(time);
    setOpen(false);
  };

  return (
    <label className="text-[12px] font-bold text-[#34405d]">
      {label}

      <div className="relative mt-1.5" ref={containerRef}>
        <button
          type="button"
          aria-expanded={open}
          aria-haspopup="dialog"
          onClick={() => {
            setNow(new Date());
            setOpen((prev) => !prev);
          }}
          className="flex h-11 w-full items-center justify-between rounded-lg border border-[#dde4f1] bg-white px-3 text-[13px] text-[#253052] outline-none transition placeholder:text-[#a7b0c0] focus:border-[#6b72f2] focus:ring-3 focus:ring-[#e9eaff]"
        >
          <span className="flex items-center gap-2">
            <Clock size={16} className="text-[#a7b0c0]" />
            {displayValue}
          </span>

          <ChevronDown
            size={16}
            className={`text-[#a7b0c0] transition ${
              open ? "rotate-180" : ""
            }`}
          />
        </button>

        <input
          type="hidden"
          name={name}
          value={safeSelectedTime}
          required={required}
        />

        {open && (
          <div className="absolute left-0 top-full z-10 mt-2 w-full rounded-lg border border-[#dde4f1] bg-white p-4 shadow-[0_10px_25px_rgba(40,55,105,0.1)]">
            <div className="mb-4 flex items-center justify-between">
              <div>
                <p className="text-[13px] font-bold text-[#253052]">
                  Demo Time
                </p>
                <p className="mt-0.5 text-[11px] font-bold text-[#a7b0c0]">
                  9:00 AM to 6:00 PM
                </p>
              </div>

              <div className="flex h-8 w-8 items-center justify-center rounded-lg bg-[#f0f4f9]">
                <Clock size={16} className="text-[#6258EA]" />
              </div>
            </div>

            {availableTimeSlots.length > 0 ? (
              <div className="grid max-h-56 grid-cols-3 gap-2 overflow-y-auto pr-1">
                {availableTimeSlots.map((slot) => {
                  const isSelected = safeSelectedTime === slot.value;

                  return (
                    <button
                      key={slot.value}
                      type="button"
                      aria-pressed={isSelected}
                      onClick={() => handleTimeSelect(slot.value)}
                      className={`h-9 rounded-lg text-[12px] font-bold transition ${
                        isSelected
                          ? "bg-[#6258EA] text-white"
                          : "border border-[#dde4f1] text-[#64708a] hover:bg-[#f0f4f9]"
                      }`}
                    >
                      {slot.label}
                    </button>
                  );
                })}
              </div>
            ) : (
              <div className="rounded-lg border border-rose-100 bg-rose-50 px-3 py-3 text-[12px] font-semibold leading-5 text-rose-600">
                Today na badha demo slots over thai gaya chhe. Please next date
                select karo.
              </div>
            )}
          </div>
        )}

        {error?.[0] && (
          <span className="mt-1 block text-[11px] text-rose-600">
            {error[0]}
          </span>
        )}
      </div>
    </label>
  );
}
