/**
 * Tests for per-status error messages in OnlineBoardSearchPage — TZ §4.1.10.1 / §4.1.12
 *
 * @vitest-environment jsdom
 */

import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen } from "@testing-library/react";
import type { OnlineBoardSearchPageProps } from "./OnlineBoardSearchPage.js";
import { ApiHttpError, ApiTimeoutError } from "@/shared/api/errors.js";
import type { UseOnlineBoardResult } from "../hooks/useOnlineBoard.js";

// ── shared mocks ──────────────────────────────────────────────────────────────

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

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>,
}));

vi.mock("@/ui/layout/PageTabs.js", () => ({
  PageTabs: () => <div data-testid="page-tabs" />,
}));

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

vi.mock("@/shared/hooks/useSearchHistory.js", () => ({
  useSearchHistory: () => ({ items: [], add: vi.fn(), clear: vi.fn() }),
}));

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

vi.mock("../hooks/useLiveBoardSearch.js", () => ({
  useLiveBoardSearch: (_params: unknown, initialFlights: unknown) => ({
    flights: initialFlights,
    connectionStatus: "idle" as const,
  }),
}));

vi.mock("../hooks/useCalendarDays.js", () => ({
  useCalendarDays: () => ({ days: [], loading: false }),
}));

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

// Hoisted mock for useOnlineBoard — overridden per test
const mockUseOnlineBoard = vi.fn<() => UseOnlineBoardResult>();
vi.mock("../hooks/useOnlineBoard.js", () => ({
  useOnlineBoard: () => mockUseOnlineBoard(),
}));

// ── fixtures ──────────────────────────────────────────────────────────────────

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

function noResult(): UseOnlineBoardResult {
  return {
    flights: [],
    loading: false,
    error: null,
    refresh: vi.fn(),
    cancel: vi.fn(),
  };
}

// ── tests ─────────────────────────────────────────────────────────────────────

describe("OnlineBoardSearchPage — §4.1.10.1 per-status error messages", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("shows BOARD.ERROR-TIMEOUT for ApiTimeoutError", async () => {
    // Dynamic import so the mock is already in place
    const { OnlineBoardSearchPage } = await import("./OnlineBoardSearchPage.js");

    mockUseOnlineBoard.mockReturnValue({
      ...noResult(),
      error: new ApiTimeoutError(30_000),
    });

    render(<OnlineBoardSearchPage params={DEPARTURE_PARAMS} />);
    expect(screen.getByTestId("search-error")).toBeTruthy();
    expect(screen.getByText("BOARD.ERROR-TIMEOUT")).toBeTruthy();
  });

  it("shows BOARD.ERROR-5XX for ApiHttpError with status 5xx", async () => {
    const { OnlineBoardSearchPage } = await import("./OnlineBoardSearchPage.js");

    mockUseOnlineBoard.mockReturnValue({
      ...noResult(),
      error: new ApiHttpError("Server error", 503),
    });

    render(<OnlineBoardSearchPage params={DEPARTURE_PARAMS} />);
    expect(screen.getByText("BOARD.ERROR-5XX")).toBeTruthy();
  });

  it("shows BOARD.ERROR-4XX for ApiHttpError with status 4xx", async () => {
    const { OnlineBoardSearchPage } = await import("./OnlineBoardSearchPage.js");

    mockUseOnlineBoard.mockReturnValue({
      ...noResult(),
      error: new ApiHttpError("Not found", 404),
    });

    render(<OnlineBoardSearchPage params={DEPARTURE_PARAMS} />);
    expect(screen.getByText("BOARD.ERROR-4XX")).toBeTruthy();
  });

  it("shows cancel button while loading (§4.1.12)", async () => {
    const { OnlineBoardSearchPage } = await import("./OnlineBoardSearchPage.js");

    mockUseOnlineBoard.mockReturnValue({
      ...noResult(),
      loading: true,
    });

    render(<OnlineBoardSearchPage params={DEPARTURE_PARAMS} />);
    expect(screen.getByTestId("cancel-search-btn")).toBeTruthy();
    expect(screen.getByText("SHARED.SEARCH-CANCEL")).toBeTruthy();
  });

  it("hides cancel button when not loading (§4.1.12)", async () => {
    const { OnlineBoardSearchPage } = await import("./OnlineBoardSearchPage.js");

    mockUseOnlineBoard.mockReturnValue(noResult());

    render(<OnlineBoardSearchPage params={DEPARTURE_PARAMS} />);
    expect(screen.queryByTestId("cancel-search-btn")).toBeNull();
  });
});
