"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { ChevronDown, ChevronLeft, ChevronRight, Calendar } from "lucide-react";

function pad(value: number) {
  return String(value).padStart(2, "0");
}

function formatLocalDate(date: Date) {
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(
    date.getDate()
  )}`;
}

function parseLocalDate(value?: string) {
  if (!value) return new Date();

  const [year, month, day] = value.split("-").map(Number);

  if (!year || !month || !day) return new Date();

  return new Date(year, month - 1, day);
}

function startOfLocalDay(date: Date) {
  return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}

export default function DatePicker({
  error,
  label,
  name,
  required,
  value,
  onChange,
  minDate,
}: {
  error?: string[];
  label: string;
  name: string;
  required?: boolean;
  value?: string;
  onChange?: (value: string) => void;
  minDate?: string;
}) {
  const [open, setOpen] = useState(false);

  const [selectedDate, setSelectedDate] = useState<Date>(() =>
    parseLocalDate(value)
  );

  const [displayMonth, setDisplayMonth] = useState<Date>(() =>
    parseLocalDate(value)
  );

  const containerRef = useRef<HTMLDivElement>(null);

  const minDateObj = useMemo(
    () => startOfLocalDay(parseLocalDate(minDate ?? formatLocalDate(new Date()))),
    [minDate]
  );

  const dateString = formatLocalDate(selectedDate);

  useEffect(() => {
    if (!value) return;

    const nextDate = parseLocalDate(value);
    const nextDateString = formatLocalDate(nextDate);

    if (nextDateString !== formatLocalDate(selectedDate)) {
      setSelectedDate(nextDate);
      setDisplayMonth(nextDate);
    }
  }, [value, selectedDate]);

  const handleDateSelect = (date: Date) => {
    const cleanDate = startOfLocalDay(date);

    if (cleanDate < minDateObj) return;

    const nextValue = formatLocalDate(cleanDate);

    setSelectedDate(cleanDate);
    onChange?.(nextValue);
    setOpen(false);
  };

  const handlePrevMonth = () => {
    setDisplayMonth(
      new Date(displayMonth.getFullYear(), displayMonth.getMonth() - 1, 1)
    );
  };

  const handleNextMonth = () => {
    setDisplayMonth(
      new Date(displayMonth.getFullYear(), displayMonth.getMonth() + 1, 1)
    );
  };

  useEffect(() => {
    function handleClickOutside(event: MouseEvent) {
      if (!containerRef.current?.contains(event.target as Node)) {
        setOpen(false);
      }
    }

    if (open) {
      document.addEventListener("mousedown", handleClickOutside);
    }

    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
  }, [open]);

  const daysInMonth = (date: Date) =>
    new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();

  const firstDayOfMonth = (date: Date) =>
    new Date(date.getFullYear(), date.getMonth(), 1).getDay();

  const days: Array<Date | null> = [];

  for (let i = 0; i < firstDayOfMonth(displayMonth); i++) {
    days.push(null);
  }

  for (let i = 1; i <= daysInMonth(displayMonth); i++) {
    days.push(new Date(displayMonth.getFullYear(), displayMonth.getMonth(), i));
  }

  const monthNames = [
    "January",
    "February",
    "March",
    "April",
    "May",
    "June",
    "July",
    "August",
    "September",
    "October",
    "November",
    "December",
  ];

  const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

  const formattedDate = selectedDate.toLocaleDateString("en-US", {
    year: "numeric",
    month: "short",
    day: "numeric",
  });

  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={() => 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">
            <Calendar size={16} className="text-[#a7b0c0]" />
            {formattedDate}
          </span>

          <ChevronDown
            size={16}
            className={`text-[#a7b0c0] transition ${
              open ? "rotate-180" : ""
            }`}
          />
        </button>

        <input
          type="hidden"
          name={name}
          value={dateString}
          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">
              <button
                type="button"
                aria-label="Previous month"
                onClick={handlePrevMonth}
                className="rounded-lg p-1 transition hover:bg-[#f0f4f9]"
              >
                <ChevronLeft size={18} className="text-[#64708a]" />
              </button>

              <div className="text-center">
                <p className="text-[13px] font-bold text-[#253052]">
                  {monthNames[displayMonth.getMonth()]}{" "}
                  {displayMonth.getFullYear()}
                </p>
              </div>

              <button
                type="button"
                aria-label="Next month"
                onClick={handleNextMonth}
                className="rounded-lg p-1 transition hover:bg-[#f0f4f9]"
              >
                <ChevronRight size={18} className="text-[#64708a]" />
              </button>
            </div>

            <div className="mb-2 grid grid-cols-7 gap-1">
              {dayNames.map((day) => (
                <div
                  key={day}
                  className="py-1 text-center text-[11px] font-bold text-[#a7b0c0]"
                >
                  {day}
                </div>
              ))}
            </div>

            <div className="grid grid-cols-7 gap-1">
              {days.map((date, idx) => {
                if (!date) return <div key={`empty-${idx}`} />;

                const cleanDate = startOfLocalDay(date);
                const isSelected =
                  formatLocalDate(cleanDate) === formatLocalDate(selectedDate);

                const isToday =
                  formatLocalDate(cleanDate) === formatLocalDate(new Date());

                const isDisabled = cleanDate < minDateObj;

                return (
                  <button
                    key={formatLocalDate(cleanDate)}
                    type="button"
                    aria-label={cleanDate.toLocaleDateString("en-US", {
                      dateStyle: "long",
                    })}
                    aria-pressed={isSelected}
                    onClick={() => handleDateSelect(cleanDate)}
                    disabled={isDisabled}
                    className={`h-8 rounded-lg text-[12px] font-bold transition ${
                      isSelected
                        ? "bg-[#6258EA] text-white"
                        : isToday
                          ? "border-2 border-[#6258EA] text-[#6258EA]"
                          : isDisabled
                            ? "cursor-not-allowed text-[#d0d8e3]"
                            : "border border-[#dde4f1] text-[#64708a] hover:bg-[#f0f4f9]"
                    }`}
                  >
                    {cleanDate.getDate()}
                  </button>
                );
              })}
            </div>

            <button
              type="button"
              onClick={() => handleDateSelect(new Date())}
              className="mt-3 h-9 w-full rounded-lg bg-[#5960ED] text-[12px] font-bold text-white transition"
            >
              Today
            </button>
          </div>
        )}

        {error?.[0] && (
          <span className="mt-1 block text-[11px] text-rose-600">
            {error[0]}
          </span>
        )}
      </div>
    </label>
  );
}