// @vitest-environment jsdom
/**
 * TZ §4.1.14.1 — WeekTabs behaviour
 *
 * Tests are labelled with the TZ rule they verify.
 */
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { render, screen, fireEvent } from "@testing-library/react";
import { WeekTabs } from "./WeekTabs.js";

// ---------------------------------------------------------------------------
// Mocks
// ---------------------------------------------------------------------------

vi.mock("@/i18n/provider.js", () => ({
  useTranslation: () => ({ t: (k: string) => k }),
}));
vi.mock("@/i18n/useLocale.js", () => ({
  useLocale: () => ({ language: "ru" }),
}));

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

/** Format Date → "yyyy-MM-dd" */
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}`;
}

/** Return the Monday of the week containing `d`. */
function mondayOf(d: Date): Date {
  const out = new Date(d);
  const day = out.getDay();
  const diff = (day + 6) % 7;
  out.setDate(out.getDate() - diff);
  out.setHours(0, 0, 0, 0);
  return out;
}

/** Add days to a Date. */
function addDays(d: Date, n: number): Date {
  const out = new Date(d);
  out.setDate(out.getDate() + n);
  return out;
}

// Pin "today" to a known Tuesday so math is predictable.
// 2026-04-21 is a Tuesday.
const FIXED_TODAY = new Date(2026, 3, 21); // April 21 2026

beforeEach(() => {
  vi.useFakeTimers();
  vi.setSystemTime(FIXED_TODAY);
});
afterEach(() => {
  vi.useRealTimers();
});

// ---------------------------------------------------------------------------
// Tests — Cluster 1: WeekTabs §4.1.14.1
// ---------------------------------------------------------------------------

describe("WeekTabs §4.1.14.1", () => {
  // TZ: "Пролистывание Табов-недель должно выполняться по 7 шт"
  it("shows exactly 7 tabs on the first page", () => {
    const monday = ymd(mondayOf(FIXED_TODAY));
    render(<WeekTabs selectedMonday={monday} onNavigate={vi.fn()} />);
    const tabs = screen.getAllByRole("button", { name: /\d/ });
    // nav buttons (prev/next) + up to 7 week tabs on page 0
    const weekTabs = tabs.filter((b) => b.getAttribute("data-testid")?.startsWith("week-tab-"));
    expect(weekTabs.length).toBeLessThanOrEqual(7);
    expect(weekTabs.length).toBeGreaterThanOrEqual(1);
  });

  // TZ: "Таб-неделя, на которую пользователь запрашивал поиск, должна быть выделена"
  it("marks the selectedMonday tab as active (aria-pressed=true)", () => {
    const monday = ymd(mondayOf(FIXED_TODAY));
    render(<WeekTabs selectedMonday={monday} onNavigate={vi.fn()} />);
    const activeTab = screen.getByTestId(`week-tab-${monday}`);
    expect(activeTab.getAttribute("aria-pressed")).toBe("true");
  });

  // TZ: "Система должна выполнить промотку к этой Табу-недели" —
  // the tab for selectedMonday must always be visible (same page).
  it("auto-scrolls to show the selected week when selectedMonday changes", () => {
    const monday0 = ymd(mondayOf(FIXED_TODAY));
    // Pick a week that is 7 weeks away (off first page of 7 tabs)
    const laterDate = addDays(FIXED_TODAY, 49); // 7 weeks ahead
    const monday7 = ymd(mondayOf(laterDate));
    const { rerender } = render(
      <WeekTabs selectedMonday={monday0} onNavigate={vi.fn()} />,
    );
    // Confirm monday0 is visible
    expect(screen.getByTestId(`week-tab-${monday0}`)).toBeTruthy();

    // Switch to a week on a different page
    rerender(<WeekTabs selectedMonday={monday7} onNavigate={vi.fn()} />);
    // The new selected week must now be rendered
    expect(screen.getByTestId(`week-tab-${monday7}`)).toBeTruthy();
    // And it must be marked active
    expect(screen.getByTestId(`week-tab-${monday7}`).getAttribute("aria-pressed")).toBe("true");
  });

  // TZ: arrow pagination — prev disabled on first page
  it("disables the prev arrow on the first page", () => {
    const monday = ymd(mondayOf(FIXED_TODAY));
    render(<WeekTabs selectedMonday={monday} onNavigate={vi.fn()} />);
    const prevBtn = screen.getByLabelText("SHARED.A11Y-PREV-PAGE") as HTMLButtonElement;
    expect(prevBtn.disabled).toBe(true);
  });

  // TZ: arrow pagination — clicking next advances page
  it("next arrow advances to the next page of 7 tabs", () => {
    const monday = ymd(mondayOf(FIXED_TODAY));
    const onNavigate = vi.fn();
    render(<WeekTabs selectedMonday={monday} onNavigate={onNavigate} />);
    const nextBtn = screen.getByLabelText("SHARED.A11Y-NEXT-PAGE");
    fireEvent.click(nextBtn);
    // After advancing, a different set of tabs should be visible
    const weekTabsAfter = screen
      .getAllByRole("button")
      .filter((b) => b.getAttribute("data-testid")?.startsWith("week-tab-"));
    // The original monday tab should no longer be visible (it was on page 0, now on page 1+)
    const originalStillVisible = weekTabsAfter.some(
      (b) => b.getAttribute("data-testid") === `week-tab-${monday}`,
    );
    expect(originalStillVisible).toBe(false);
  });

  // TZ: "нижней границы валидации -1 день от текущего дня"
  // The very first tab must be the Monday of the week containing today-1.
  it("starts from the week containing yesterday (lower bound -1 day)", () => {
    const yesterday = addDays(FIXED_TODAY, -1);
    const yesterdayMonday = ymd(mondayOf(yesterday));
    const monday = ymd(mondayOf(FIXED_TODAY));
    render(<WeekTabs selectedMonday={monday} onNavigate={vi.fn()} />);
    // The first week-tab rendered must be the monday anchoring yesterday's week.
    const firstWeekTab = screen
      .getAllByRole("button")
      .find((b) => b.getAttribute("data-testid")?.startsWith("week-tab-") &&
                  !b.getAttribute("data-testid")?.startsWith("week-tab-placeholder-"));
    // 2026-04-21 (Tue) → yesterday is Mon 2026-04-20 → mondayOf = 2026-04-20
    expect(firstWeekTab?.getAttribute("data-testid")).toBe(`week-tab-${yesterdayMonday}`);
  });

  // TZ: "если последний активный Таб-недля не является завершающим в разбивке
  // (по 7 шт), то должен быть «добор» Табов-недль до 7 шт, но они не должны
  // быть активными. В этом случае, элемент промотки вправо должен быть неактивный."
  it("fills the last page to 7 tabs with inactive placeholders and disables next arrow", () => {
    // Navigate to the last page by clicking next until next is disabled
    const monday = ymd(mondayOf(FIXED_TODAY));
    render(<WeekTabs selectedMonday={monday} onNavigate={vi.fn()} />);
    const nextBtn = screen.getByLabelText("SHARED.A11Y-NEXT-PAGE");

    // Click next until it becomes disabled
    let safety = 0;
    while (!nextBtn.hasAttribute("disabled") && safety < 10) {
      fireEvent.click(nextBtn);
      safety++;
    }

    // On the last page, next must be disabled
    expect((nextBtn as HTMLButtonElement).disabled).toBe(true);

    // All 7 tab slots must be rendered (active + placeholders)
    const allWeekTabBtns = screen
      .getAllByRole("button")
      .filter((b) => b.getAttribute("data-testid")?.startsWith("week-tab-"));
    expect(allWeekTabBtns.length).toBe(7);

    // Placeholder tabs must each be disabled (HTMLButtonElement.disabled)
    const placeholders = allWeekTabBtns.filter(
      (b) => b.getAttribute("data-testid")?.startsWith("week-tab-placeholder-"),
    );
    placeholders.forEach((b) => {
      expect((b as HTMLButtonElement).disabled).toBe(true);
    });
  });

  // TZ: clicking a tab fires onNavigate with the Monday yyyy-MM-dd
  it("fires onNavigate with the monday ymd when a tab is clicked", () => {
    const monday = ymd(mondayOf(FIXED_TODAY));
    const onNavigate = vi.fn();
    render(<WeekTabs selectedMonday={monday} onNavigate={onNavigate} />);
    // Click the next-page to get different tabs visible
    const nextBtn = screen.getByLabelText("SHARED.A11Y-NEXT-PAGE");
    fireEvent.click(nextBtn);
    const anyTab = screen
      .getAllByRole("button")
      .find((b) => b.getAttribute("data-testid")?.startsWith("week-tab-"));
    expect(anyTab).toBeTruthy();
    fireEvent.click(anyTab!);
    expect(onNavigate).toHaveBeenCalledWith(
      anyTab!.getAttribute("data-testid")!.replace("week-tab-", ""),
    );
  });
});
