import {
  addWeeks,
  buildCalendarMonth,
  DateTime,
  getWeekStart,
  toDateOnly,
} from "@batch-cooking/date-tools";
import { WEEK_DAYS } from "@batch-cooking/shared";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import "./week-navigator.scss";

/** "17 au 23 août 2026" — collapses the month/year to just the end date when both ends of the week share it, spells it out on both ends otherwise (e.g. a week straddling two months). */
function formatWeekRange(weekStart: DateTime): string {
  const weekEnd = weekStart.plus({ days: 6 });
  const sameMonth = weekStart.hasSame(weekEnd, "month");
  const startLabel = weekStart.toLocaleString(
    sameMonth ? { day: "numeric" } : { day: "numeric", month: "long" },
    { locale: "fr" },
  );
  const endLabel = weekEnd.toLocaleString(
    { day: "numeric", month: "long", year: "numeric" },
    { locale: "fr" },
  );
  return `${startLabel} au ${endLabel}`;
}

/**
 * Arrows + clickable label opening {@link CalendarPopover} — week-selection
 * UI shared by any page organized around "one week at a time" (originally
 * `PlanningPage`'s own grid, now also `ShoppingListPage` — both just need a
 * `weekStart` in/out, neither cares how the other renders its own content
 * for that week). Copy comes from `common.weekNav.*`/`common.calendar.*`/
 * `common.days.*` rather than `planning.*` — generic enough ("Semaine
 * précédente", day names) to not read as planning-specific from a page that
 * isn't the planning grid.
 */
export function WeekNavigator({
  weekStart,
  onChangeWeek,
}: {
  weekStart: DateTime;
  onChangeWeek: (weekStart: DateTime) => void;
}) {
  const { t } = useTranslation();
  const [isCalendarOpen, setIsCalendarOpen] = useState(false);
  const isThisWeek = weekStart.hasSame(getWeekStart(DateTime.utc()), "day");

  return (
    <div className="week-nav">
      <button
        type="button"
        className="week-nav__arrow"
        title={t("common.weekNav.prevWeek")}
        onClick={() => onChangeWeek(addWeeks(weekStart, -1))}
      >
        ‹
      </button>

      <button
        type="button"
        className="week-nav__label"
        onClick={() => setIsCalendarOpen((open) => !open)}
      >
        📅 {t("common.weekNav.label", { range: formatWeekRange(weekStart) })}
        {isThisWeek && <span className="today-badge">{t("common.weekNav.thisWeek")}</span>}
      </button>

      <button
        type="button"
        className="week-nav__arrow"
        title={t("common.weekNav.nextWeek")}
        onClick={() => onChangeWeek(addWeeks(weekStart, 1))}
      >
        ›
      </button>

      {isCalendarOpen && (
        <CalendarPopover
          selectedWeekStart={weekStart}
          onSelectDay={(day) => {
            onChangeWeek(getWeekStart(day));
            setIsCalendarOpen(false);
          }}
          onClose={() => setIsCalendarOpen(false)}
        />
      )}
    </div>
  );
}

/** Month calendar letting the visitor jump to any week at once — selecting a day selects its whole (Monday-first) week. Closes itself on an outside click. */
function CalendarPopover({
  selectedWeekStart,
  onSelectDay,
  onClose,
}: {
  selectedWeekStart: DateTime;
  onSelectDay: (day: DateTime) => void;
  onClose: () => void;
}) {
  const { t } = useTranslation();
  // Its own state: browsing to a different month to pick a week there
  // shouldn't jump back every render — only re-anchors when the popover is
  // first opened (`selectedWeekStart` at that point), not while it's open.
  const [visibleMonth, setVisibleMonth] = useState(() => selectedWeekStart.startOf("month"));
  const popoverRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    function handleClickOutside(e: MouseEvent) {
      if (popoverRef.current && !popoverRef.current.contains(e.target as Node)) {
        onClose();
      }
    }
    document.addEventListener("mousedown", handleClickOutside);
    return () => document.removeEventListener("mousedown", handleClickOutside);
  }, [onClose]);

  const today = toDateOnly(DateTime.utc());
  const selectedWeekEnd = selectedWeekStart.plus({ days: 6 });
  const weeks = buildCalendarMonth(visibleMonth);

  return (
    <div className="calendar-popover" ref={popoverRef}>
      <div className="calendar-popover__header">
        <button
          type="button"
          title={t("common.calendar.prevMonth")}
          onClick={() => setVisibleMonth((month) => month.minus({ months: 1 }))}
        >
          ‹
        </button>
        <span>
          {visibleMonth.toLocaleString({ month: "long", year: "numeric" }, { locale: "fr" })}
        </span>
        <button
          type="button"
          title={t("common.calendar.nextMonth")}
          onClick={() => setVisibleMonth((month) => month.plus({ months: 1 }))}
        >
          ›
        </button>
      </div>

      <div className="calendar-grid">
        {WEEK_DAYS.map((weekDay) => (
          <span key={weekDay} className="calendar-grid__weekday">
            {t(`common.days.${weekDay}`).charAt(0)}
          </span>
        ))}

        {weeks.flat().map((day) => {
          const classNames = ["calendar-grid__day"];
          if (!day.hasSame(visibleMonth, "month")) classNames.push("calendar-grid__day--muted");
          if (day >= selectedWeekStart && day <= selectedWeekEnd) {
            classNames.push("calendar-grid__day--in-selected-week");
          }
          if (day.hasSame(today, "day")) classNames.push("calendar-grid__day--today");

          return (
            <button
              key={day.toISO()}
              type="button"
              className={classNames.join(" ")}
              onClick={() => onSelectDay(day)}
            >
              {day.day}
            </button>
          );
        })}
      </div>
    </div>
  );
}
