"use client";

import { useEffect, useRef, useState } from "react";
import { getDefaultDateRange } from "@/lib/dashboard/owner-dashboard";
import { MaterialIcon } from "../icons/nav-icons";

export type OwnerDateRange = {
  start: Date;
  end: Date;
};

type OwnerDateRangePickerProps = {
  value: OwnerDateRange;
  label: string;
  placeholder?: string;
  onChange: (range: OwnerDateRange) => void;
  variant?: "button" | "field" | "tab";
  active?: boolean;
  autoOpen?: boolean;
  className?: string;
};

const WEEKDAYS = ["Mi", "Se", "Se", "Ra", "Ka", "Ju", "Sa"] as const;

const monthLabelFormatter = new Intl.DateTimeFormat("id-ID", {
  month: "short",
  year: "numeric",
});

function startOfDay(date: Date) {
  return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}

function isSameDay(a: Date, b: Date) {
  return (
    a.getFullYear() === b.getFullYear() &&
    a.getMonth() === b.getMonth() &&
    a.getDate() === b.getDate()
  );
}

function isBeforeDay(a: Date, b: Date) {
  return startOfDay(a).getTime() < startOfDay(b).getTime();
}

function isAfterDay(a: Date, b: Date) {
  return startOfDay(a).getTime() > startOfDay(b).getTime();
}

function buildCalendarDays(visibleMonth: Date) {
  const year = visibleMonth.getFullYear();
  const month = visibleMonth.getMonth();
  const firstOfMonth = new Date(year, month, 1);
  const startOffset = firstOfMonth.getDay();
  const gridStart = new Date(year, month, 1 - startOffset);
  const daysInMonth = new Date(year, month + 1, 0).getDate();
  const totalCells = Math.ceil((startOffset + daysInMonth) / 7) * 7;

  return Array.from({ length: totalCells }, (_, index) => {
    const date = new Date(gridStart);
    date.setDate(gridStart.getDate() + index);
    return date;
  });
}

function getDayTone(
  date: Date,
  draftStart: Date | null,
  draftEnd: Date | null,
): "default" | "start" | "end" | "middle" | "single" {
  if (!draftStart) {
    return "default";
  }

  if (!draftEnd || isSameDay(draftStart, draftEnd)) {
    return isSameDay(date, draftStart) ? "single" : "default";
  }

  const start = isBeforeDay(draftStart, draftEnd) ? draftStart : draftEnd;
  const end = isBeforeDay(draftStart, draftEnd) ? draftEnd : draftStart;

  if (isSameDay(date, start)) {
    return "start";
  }

  if (isSameDay(date, end)) {
    return "end";
  }

  if (isAfterDay(date, start) && isBeforeDay(date, end)) {
    return "middle";
  }

  return "default";
}

function dayButtonClassName(
  tone: ReturnType<typeof getDayTone>,
  isCurrentMonth: boolean,
) {
  const base =
    "text-m-medium flex size-[32.86px] items-center justify-center transition-colors";

  if (tone === "single") {
    return `${base} rounded-lg bg-secondary-500 text-neutral-100`;
  }

  if (tone === "start") {
    return `${base} rounded-l-lg bg-secondary-500 text-neutral-100`;
  }

  if (tone === "end") {
    return `${base} rounded-r-lg bg-secondary-500 text-neutral-100`;
  }

  if (tone === "middle") {
    return `${base} bg-secondary-100 text-neutral-100`;
  }

  return `${base} bg-neutral-10 ${
    isCurrentMonth ? "text-neutral-100 hover:bg-neutral-20" : "text-[#9e9e9e]"
  }`;
}

export function OwnerDateRangePicker({
  value,
  label,
  placeholder = "Pilih rentang tanggal",
  onChange,
  variant = "button",
  active = false,
  autoOpen = false,
  className,
}: OwnerDateRangePickerProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const [isOpen, setIsOpen] = useState(autoOpen);
  const [visibleMonth, setVisibleMonth] = useState(
    () => new Date(value.start.getFullYear(), value.start.getMonth(), 1),
  );
  const [draftStart, setDraftStart] = useState<Date | null>(value.start);
  const [draftEnd, setDraftEnd] = useState<Date | null>(value.end);

  const calendarDays = buildCalendarDays(visibleMonth);
  const monthLabel = monthLabelFormatter.format(visibleMonth);
  const isField = variant === "field";
  const isTab = variant === "tab";
  const displayLabel = label.trim() || placeholder;
  const isPlaceholder = label.trim().length === 0;

  useEffect(() => {
    if (!autoOpen) {
      return;
    }

    setVisibleMonth(
      new Date(value.start.getFullYear(), value.start.getMonth(), 1),
    );
    setDraftStart(startOfDay(value.start));
    setDraftEnd(startOfDay(value.end));
    setIsOpen(true);
  }, [autoOpen]);

  useEffect(() => {
    if (!isOpen) {
      return;
    }

    function handleClickOutside(event: MouseEvent) {
      if (
        containerRef.current &&
        !containerRef.current.contains(event.target as Node)
      ) {
        setIsOpen(false);
      }
    }

    function handleEscape(event: KeyboardEvent) {
      if (event.key === "Escape") {
        setIsOpen(false);
      }
    }

    document.addEventListener("mousedown", handleClickOutside);
    document.addEventListener("keydown", handleEscape);

    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
      document.removeEventListener("keydown", handleEscape);
    };
  }, [isOpen]);

  function openPicker() {
    setVisibleMonth(
      new Date(value.start.getFullYear(), value.start.getMonth(), 1),
    );
    setDraftStart(startOfDay(value.start));
    setDraftEnd(startOfDay(value.end));
    setIsOpen(true);
  }

  function handleToggle() {
    if (isOpen) {
      setIsOpen(false);
      return;
    }

    openPicker();
  }

  function shiftMonth(delta: number) {
    setVisibleMonth(
      (prev) => new Date(prev.getFullYear(), prev.getMonth() + delta, 1),
    );
  }

  function handleSelectDay(date: Date) {
    const selected = startOfDay(date);

    if (!draftStart || (draftStart && draftEnd)) {
      setDraftStart(selected);
      setDraftEnd(null);
      return;
    }

    const start = isBeforeDay(selected, draftStart) ? selected : draftStart;
    const end = isBeforeDay(selected, draftStart) ? draftStart : selected;

    setDraftStart(start);
    setDraftEnd(end);
    onChange({ start, end });
    setIsOpen(false);
  }

  function handleClear() {
    const fallback = getDefaultDateRange();
    const start = startOfDay(fallback.start);
    const end = startOfDay(fallback.end);

    setDraftStart(start);
    setDraftEnd(end);
    setVisibleMonth(new Date(start.getFullYear(), start.getMonth(), 1));
    onChange({ start, end });
    setIsOpen(false);
  }

  return (
    <div
      ref={containerRef}
      className={`relative ${isField || isTab ? "w-full" : "shrink-0"} ${className ?? ""}`}
    >
      <button
        type="button"
        onClick={handleToggle}
        aria-expanded={isOpen}
        aria-haspopup="dialog"
        aria-pressed={isTab ? active : undefined}
        className={
          isTab
            ? `text-m-medium flex h-full min-h-9 w-full cursor-pointer items-center justify-center gap-1.5 rounded-md px-2 py-2 outline-none transition-colors focus-visible:ring-2 focus-visible:ring-primary-500 ${
                active
                  ? "bg-neutral-10 text-primary-600 shadow-sm"
                  : "text-neutral-80 hover:bg-neutral-10/70 hover:text-neutral-100"
              }`
            : isField
              ? `text-m-regular flex h-10 w-full cursor-pointer items-center justify-between gap-2 rounded-lg border bg-neutral-10 px-[22px] py-2 text-left text-neutral-100 outline-none focus:border-primary-500 ${
                  active
                    ? "border-primary-500"
                    : "border-neutral-40"
                }`
              : "text-m-regular inline-flex h-10 shrink-0 cursor-pointer items-center gap-2 rounded-lg border border-neutral-40 bg-neutral-10 px-4 py-2 text-neutral-100"
        }
      >
        {isTab ? (
          <>
            <MaterialIcon
              name="calendar_today"
              size={16}
              className="shrink-0"
            />
            <span className="truncate">{displayLabel}</span>
          </>
        ) : isField ? (
          <>
            <span
              className={`truncate ${isPlaceholder ? "text-neutral-70" : ""}`}
            >
              {displayLabel}
            </span>
            <MaterialIcon
              name="calendar_today"
              size={18}
              className="shrink-0 text-neutral-80"
            />
          </>
        ) : (
          <>
            <MaterialIcon
              name="calendar_today"
              size={18}
              className="text-neutral-80"
            />
            <span>{displayLabel}</span>
          </>
        )}
      </button>

      {isOpen && (
        <div
          role="dialog"
          aria-label="Pilih rentang tanggal"
          className={`absolute top-[calc(100%+4px)] z-50 w-[250px] overflow-hidden rounded-lg border border-neutral-40 bg-neutral-10 shadow-sm ${
            isField || isTab ? "left-0 sm:left-auto sm:right-0" : "right-0"
          }`}
        >
          <div className="flex flex-col p-2.5">
            <div className="flex items-center justify-between px-0 py-1">
              <button
                type="button"
                onClick={() => shiftMonth(-1)}
                aria-label="Bulan sebelumnya"
                className="inline-flex size-4 items-center justify-center text-neutral-100"
              >
                <MaterialIcon name="keyboard_double_arrow_left" size={16} />
              </button>
              <p className="text-m-medium capitalize text-neutral-100">
                {monthLabel}
              </p>
              <button
                type="button"
                onClick={() => shiftMonth(1)}
                aria-label="Bulan berikutnya"
                className="inline-flex size-4 items-center justify-center text-neutral-100"
              >
                <MaterialIcon name="keyboard_double_arrow_right" size={16} />
              </button>
            </div>

            <div className="grid grid-cols-7">
              {WEEKDAYS.map((weekday, index) => (
                <div
                  key={`${weekday}-${index}`}
                  className="text-m-medium flex h-8 items-center justify-center text-neutral-100"
                >
                  {weekday}
                </div>
              ))}
            </div>

            <div className="grid grid-cols-7">
              {calendarDays.map((date) => {
                const isCurrentMonth =
                  date.getMonth() === visibleMonth.getMonth();
                const tone = getDayTone(date, draftStart, draftEnd);

                return (
                  <button
                    key={date.toISOString()}
                    type="button"
                    onClick={() => handleSelectDay(date)}
                    className={dayButtonClassName(tone, isCurrentMonth)}
                  >
                    {date.getDate()}
                  </button>
                );
              })}
            </div>
          </div>

          <div className="flex items-center justify-center border-t border-neutral-40 py-2.5">
            <button
              type="button"
              onClick={handleClear}
              className="text-s-medium text-neutral-80 hover:text-neutral-100"
            >
              Hapus
            </button>
          </div>
        </div>
      )}
    </div>
  );
}
