/**
 * Integration tests for the Online Board search page.
 *
 * Verifies FlightList renders with mocked API data, connection status
 * badge, and calendar strip.
 *
 * @vitest-environment jsdom
 */

import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen } from "@testing-library/react";
import { OnlineBoardSearchPage } from "@/features/online-board/components/OnlineBoardSearchPage.js";
import type { OnlineBoardSearchPageProps } from "@/features/online-board/components/OnlineBoardSearchPage.js";
import { ALL_FLIGHTS, CALENDAR_DAYS } from "./fixtures.js";

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

vi.mock("@modern-js/runtime/router", () => ({
  useNavigate: () => vi.fn(),
  useParams: () => ({ lang: "ru-ru" }),
  Link: ({ children, ...props }: Record<string, unknown>) =>
    <a {...props}>{children as React.ReactNode}</a>,
}));

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

// Mock layout components to avoid transitive dependency issues
vi.mock("@/ui/layout/PageTabs.js", () => ({
  PageTabs: () => <div data-testid="page-tabs" />,
}));

vi.mock("@/features/online-board/components/OnlineBoardFilter.js", () => ({
  OnlineBoardFilter: () => <div data-testid="online-board-filter" />,
}));

vi.mock("@/features/flights-map/hooks/useFeatureFlag.js", () => ({
  useFeatureFlag: () => false,
}));

const mockUseOnlineBoard = vi.fn();
vi.mock("@/features/online-board/hooks/useOnlineBoard.js", () => ({
  useOnlineBoard: (...args: unknown[]) => mockUseOnlineBoard(...args),
}));

const mockUseLiveBoardSearch = vi.fn();
vi.mock("@/features/online-board/hooks/useLiveBoardSearch.js", () => ({
  useLiveBoardSearch: (...args: unknown[]) => mockUseLiveBoardSearch(...args),
}));

const mockUseCalendarDays = vi.fn();
vi.mock("@/features/online-board/hooks/useCalendarDays.js", () => ({
  useCalendarDays: (...args: unknown[]) => mockUseCalendarDays(...args),
}));

vi.mock("@/shared/dictionaries/index.js", () => ({
  useDictionaries: () => ({ dictionaries: null, loading: false, error: null }),
}));

// FlightActions (rendered inside each expanded flight row) pulls the
// buy/registration window lengths from useAppSettings, which itself
// needs the ApiClientProvider. Integration tests don't wire the real
// API client, so mock useAppSettings with the Angular defaults.
vi.mock("@/shared/hooks/useAppSettings.js", () => ({
  useAppSettings: () => ({
    onlineboardSearchFrom: 1,
    onlineboardSearchTo: 7,
    scheduleSearchFrom: 1,
    scheduleSearchTo: 330,
    flightStatusAvailableFromHours: 2,
    buyTicketMinHours: 2,
    buyTicketMaxHours: 72,
    loading: false,
    error: null,
  }),
}));

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

const DEPARTURE_PARAMS: OnlineBoardSearchPageProps["params"] = {
  type: "departure",
  station: "SVO",
  date: "20250115",
};

function setupMocksWithData() {
  mockUseOnlineBoard.mockReturnValue({
    flights: ALL_FLIGHTS,
    loading: false,
    error: null,
    refresh: vi.fn(),
  });
  mockUseLiveBoardSearch.mockImplementation(
    (_params: unknown, initialFlights: unknown) => ({
      flights: initialFlights,
      connectionStatus: "idle" as const,
    }),
  );
  mockUseCalendarDays.mockReturnValue({
    days: CALENDAR_DAYS,
    loading: false,
  });
}

function setupMocksEmpty() {
  mockUseOnlineBoard.mockReturnValue({
    flights: [],
    loading: false,
    error: null,
    refresh: vi.fn(),
  });
  mockUseLiveBoardSearch.mockImplementation(
    (_params: unknown, initialFlights: unknown) => ({
      flights: initialFlights,
      connectionStatus: "idle" as const,
    }),
  );
  mockUseCalendarDays.mockReturnValue({
    days: [],
    loading: false,
  });
}

function setupMocksLoading() {
  mockUseOnlineBoard.mockReturnValue({
    flights: [],
    loading: true,
    error: null,
    refresh: vi.fn(),
  });
  mockUseLiveBoardSearch.mockImplementation(
    (_params: unknown, initialFlights: unknown) => ({
      flights: initialFlights,
      connectionStatus: "idle" as const,
    }),
  );
  mockUseCalendarDays.mockReturnValue({
    days: [],
    loading: true,
  });
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------

describe("Flight search page integration", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("renders search page container with data", () => {
    setupMocksWithData();
    render(<OnlineBoardSearchPage params={DEPARTURE_PARAMS} />);
    expect(screen.getByTestId("online-board-search")).toBeTruthy();
  });

  it("renders flight cards when flights are returned", () => {
    setupMocksWithData();
    render(<OnlineBoardSearchPage params={DEPARTURE_PARAMS} />);
    // FlightCard renders the flight number as "SU 0100"
    const flightCards = screen.getAllByText(/SU 0\d{3}/);
    expect(flightCards.length).toBeGreaterThanOrEqual(2);
  });

  it("renders empty state when no flights returned", () => {
    setupMocksEmpty();
    render(<OnlineBoardSearchPage params={DEPARTURE_PARAMS} />);
    expect(screen.getByText("SHARED.FLIGHTS-NOT-FOUND")).toBeTruthy();
  });

  it("renders calendar strip (DayTabs) with pagination arrows", () => {
    setupMocksWithData();
    render(<OnlineBoardSearchPage params={DEPARTURE_PARAMS} />);
    // Pre-refactor the sticky strip was an ad-hoc DOM with data-testid
    // "calendar-strip". We now use the shared <DayTabs> component, whose
    // root testid is "day-tabs". Assert its structural markers instead.
    expect(screen.getByTestId("day-tabs")).toBeTruthy();
    expect(screen.getByTestId("day-tabs-prev")).toBeTruthy();
    expect(screen.getByTestId("day-tabs-next")).toBeTruthy();
  });

  it("renders live connection badge when SignalR is live", () => {
    mockUseOnlineBoard.mockReturnValue({
      flights: ALL_FLIGHTS,
      loading: false,
      error: null,
      refresh: vi.fn(),
    });
    mockUseLiveBoardSearch.mockImplementation(
      (_params: unknown, initialFlights: unknown) => ({
        flights: initialFlights,
        connectionStatus: "live" as const,
      }),
    );
    mockUseCalendarDays.mockReturnValue({ days: [], loading: false });

    render(<OnlineBoardSearchPage params={DEPARTURE_PARAMS} />);
    expect(screen.getByText("SHARED.CONNECTION-LIVE")).toBeTruthy();
  });

  it("renders offline badge when SignalR disconnects", () => {
    mockUseOnlineBoard.mockReturnValue({
      flights: ALL_FLIGHTS,
      loading: false,
      error: null,
      refresh: vi.fn(),
    });
    mockUseLiveBoardSearch.mockImplementation(
      (_params: unknown, initialFlights: unknown) => ({
        flights: initialFlights,
        connectionStatus: "offline" as const,
      }),
    );
    mockUseCalendarDays.mockReturnValue({ days: [], loading: false });

    render(<OnlineBoardSearchPage params={DEPARTURE_PARAMS} />);
    expect(screen.getByText("SHARED.CONNECTION-OFFLINE")).toBeTruthy();
  });

  it("passes correct search params for departure type", () => {
    setupMocksWithData();
    render(<OnlineBoardSearchPage params={DEPARTURE_PARAMS} />);

    const callArgs = mockUseOnlineBoard.mock.calls[0]?.[0] as Record<string, string>;
    expect(callArgs).toEqual({
      dateFrom: "2025-01-15T00:00:00",
      dateTo: "2025-01-16T00:00:00",
      departure: "SVO",
    });
  });

  it("passes correct search params for flight type", () => {
    setupMocksWithData();
    render(
      <OnlineBoardSearchPage
        params={{
          type: "flight",
          carrier: "SU",
          flightNumber: "100",
          date: "20250115",
        }}
      />,
    );

    const callArgs = mockUseOnlineBoard.mock.calls[0]?.[0] as Record<string, string>;
    expect(callArgs).toEqual({
      dateFrom: "2025-01-15T00:00:00",
      dateTo: "2025-01-16T00:00:00",
      flightNumber: "SU100",
    });
  });

  it("passes correct search params for route type", () => {
    setupMocksWithData();
    render(
      <OnlineBoardSearchPage
        params={{
          type: "route",
          departure: "SVO",
          arrival: "JFK",
          date: "20250115",
        }}
      />,
    );

    const callArgs = mockUseOnlineBoard.mock.calls[0]?.[0] as Record<string, string>;
    expect(callArgs).toEqual({
      dateFrom: "2025-01-15T00:00:00",
      dateTo: "2025-01-16T00:00:00",
      departure: "SVO",
      arrival: "JFK",
    });
  });

  it("renders loading skeleton when loading", () => {
    setupMocksLoading();
    const { container } = render(
      <OnlineBoardSearchPage params={DEPARTURE_PARAMS} />,
    );
    // FlightListSkeleton renders skeleton elements
    const skeletons = container.querySelectorAll(".flight-list-skeleton__row");
    expect(skeletons.length).toBeGreaterThan(0);
  });
});
