/**
 * Weekly date-range tabs for the schedule pages.
 *
 * Mirrors Angular's `week-tabs` (Monday-anchored 7-day windows shown
 * as `13 апр - 19 апр`). Distinct from the onlineboard's `DayTabs`
 * which is daily.
 *
 * Emits the Monday yyyy-MM-dd of the chosen week on click.
 *
 * Per TZ §4.1.14.1:
 * - Active range: [today-1 day, today+330 days].
 * - Pages of exactly 7 tabs; last page is padded with disabled placeholders
 *   to fill to 7 when the last active week is not the final slot.
 * - Next arrow is disabled on the last page (including when padded).
 * - Clicking a tab auto-scrolls (page jumps) to show the selected week.
 */

import { type FC, useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "@/i18n/provider.js";
import { scheduleWindowBounds } from "@/shared/dateWindow.js";
import "./WeekTabs.scss";

const PAGE_SIZE = 7;

export interface WeekTabsProps {
  /** Monday yyyy-MM-dd of the currently active week. */
  selectedMonday: string;
  /** Fired with the Monday yyyy-MM-dd of the chosen week. */
  onNavigate: (mondayYmd: string) => void;
}

interface WeekEntry {
  monday: Date;
  sunday: Date;
  ymd: string;
  label: string;
}

function startOfWeekMonday(d: Date): Date {
  const out = new Date(d);
  const day = out.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat
  const diff = (day + 6) % 7; // distance back to Monday
  out.setDate(out.getDate() - diff);
  out.setHours(0, 0, 0, 0);
  return out;
}

function ymd(d: Date): string {
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, "0");
  const day = String(d.getDate()).padStart(2, "0");
  return `${y}-${m}-${day}`;
}

export const WeekTabs: FC<WeekTabsProps> = ({ selectedMonday, onNavigate }) => {
  const { t } = useTranslation();
  // Short month abbreviations come from `MONTH-SHORT.{1..12}`, same
  // lookup table as Angular's `DatesTranslationService.getShortDateString`
  // ("27 апр." / "3 май." for ru; "Apr" / "May" for en).
  const shortDay = useCallback(
    (d: Date) => `${d.getDate()} ${t(`MONTH-SHORT.${d.getMonth() + 1}`)}`,
    [t],
  );

  // Build the active weeks list anchored to the schedule window
  // [-1 day, +330 days] per TZ §4.1.14.1.
  const weeks: WeekEntry[] = useMemo(() => {
    const [windowMin, windowMax] = scheduleWindowBounds();
    const out: WeekEntry[] = [];
    // Start at the Monday of the week that contains windowMin.
    const start = startOfWeekMonday(windowMin);
    // Iterate week by week until the Monday is beyond windowMax.
    for (let i = 0; ; i++) {
      const monday = new Date(start);
      monday.setDate(start.getDate() + i * 7);
      if (monday > windowMax) break;
      const sunday = new Date(monday);
      sunday.setDate(monday.getDate() + 6);
      out.push({
        monday,
        sunday,
        ymd: ymd(monday),
        label: `${shortDay(monday)} - ${shortDay(sunday)}`,
      });
    }
    return out;
  }, [shortDay]);

  // Derive the page that contains selectedMonday. Re-derives whenever
  // selectedMonday or weeks change so navigation to a new week auto-scrolls
  // the tab strip to show it (TZ §4.1.14.1: "Система должна выполнить
  // промотку к этой Табу-недели").
  const selectedPage = useMemo(() => {
    const idx = weeks.findIndex((w) => w.ymd === selectedMonday);
    if (idx < 0) return 0;
    return Math.floor(idx / PAGE_SIZE);
  }, [weeks, selectedMonday]);

  const [page, setPage] = useState(selectedPage);

  // Sync page when selectedMonday changes (e.g. user picks a week from
  // a different page via the filter or URL navigation).
  useEffect(() => {
    setPage(selectedPage);
  }, [selectedPage]);

  // Total active pages (without padding).
  const activeTotalPages = Math.max(1, Math.ceil(weeks.length / PAGE_SIZE));

  // Per TZ §4.1.14.1: "если последний активный Таб-недля не является
  // завершающим в разбивке (по 7 шт), то должен быть «добор» Табов-недль
  // до 7 шт, но они не должны быть активными. В этом случае, элемент
  // промотки вправо должен быть неактивный."
  // The next button is disabled on the last active page (page === activeTotalPages-1).
  const isLastPage = page >= activeTotalPages - 1;

  // Slice the active weeks for the current page.
  const activeSlice = weeks.slice(page * PAGE_SIZE, page * PAGE_SIZE + PAGE_SIZE);

  // Pad with null placeholders when the last page has fewer than PAGE_SIZE entries.
  const paddedCount = isLastPage ? PAGE_SIZE - activeSlice.length : 0;

  return (
    <nav
      className="week-tabs"
      data-testid="week-tabs"
      aria-label={t("SCHEDULE.TITLE")}
    >
      <button
        type="button"
        className="week-tabs__nav week-tabs__nav--prev"
        disabled={page === 0}
        onClick={() => setPage((p) => Math.max(0, p - 1))}
        aria-label={t("SHARED.A11Y-PREV-PAGE")}
      >
        <svg viewBox="0 0 8 12" width="8" height="12" aria-hidden="true">
          <path d="M7 1L2 6L7 11" stroke="currentColor" strokeWidth="1.6" fill="none" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      </button>
      <div className="week-tabs__list">
        {activeSlice.map((w) => {
          const isActive = w.ymd === selectedMonday;
          return (
            <button
              key={w.ymd}
              type="button"
              className={`week-tabs__tab${isActive ? " week-tabs__tab--active" : ""}`}
              aria-pressed={isActive}
              data-active={isActive ? "true" : "false"}
              data-testid={`week-tab-${w.ymd}`}
              onClick={() => onNavigate(w.ymd)}
            >
              {w.label}
            </button>
          );
        })}
        {/* Inactive placeholder tabs to fill the last page to PAGE_SIZE */}
        {Array.from({ length: paddedCount }).map((_, i) => (
          <button
            key={`placeholder-${i}`}
            type="button"
            className="week-tabs__tab week-tabs__tab--placeholder"
            aria-pressed={false}
            disabled
            data-testid={`week-tab-placeholder-${i}`}
            tabIndex={-1}
          >
            {" "}
          </button>
        ))}
      </div>
      <button
        type="button"
        className="week-tabs__nav week-tabs__nav--next"
        disabled={isLastPage}
        onClick={() => setPage((p) => Math.min(activeTotalPages - 1, p + 1))}
        aria-label={t("SHARED.A11Y-NEXT-PAGE")}
      >
        <svg viewBox="0 0 8 12" width="8" height="12" aria-hidden="true">
          <path d="M1 1L6 6L1 11" stroke="currentColor" strokeWidth="1.6" fill="none" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      </button>
    </nav>
  );
};
