import React from "react";
import "@testing-library/jest-dom";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";

import { api } from "./api";
import { I18nProvider } from "./i18n/I18nProvider";
import OperationsPage from "./views/OperationsPage";

jest.mock("./api", () => ({
  api: {
    get: jest.fn(),
    post: jest.fn(),
    delete: jest.fn(),
    interceptors: { request: { use: jest.fn() }, response: { use: jest.fn() } },
  },
  getApiErrorMessage: (_error: unknown, fallback?: string) => fallback || "Request failed.",
}));

const mockedApi = api as jest.Mocked<typeof api>;

function renderPage() {
  return render(<I18nProvider><OperationsPage /></I18nProvider>);
}

const operation = {
  id: "11111111-1111-1111-1111-111111111111",
  taskType: "strategy_snapshot",
  status: "running",
  createdAtUtc: "2026-08-02T12:00:00Z",
  progressStage: "Analysing role",
  progressPercent: 40,
  canCancel: true,
  canRetry: false,
};

const notification = {
  id: "22222222-2222-2222-2222-222222222222",
  operationId: operation.id,
  kind: "operation_failed",
  title: "Operation failed",
  message: "A background operation failed. Review it for details.",
  createdAtUtc: "2026-08-02T12:05:00Z",
  readAtUtc: null,
};

beforeEach(() => {
  jest.clearAllMocks();
  window.localStorage.clear();
  mockedApi.get.mockImplementation((url: string) => Promise.resolve({
    data: url.startsWith("/operations") ? [operation] : [notification],
  } as any));
  mockedApi.post.mockResolvedValue({ data: {} } as any);
  mockedApi.delete.mockResolvedValue({ data: {} } as any);
});

test("shows persistent operation and notification states with accessible actions", async () => {
  renderPage();

  expect(await screen.findByText("strategy_snapshot")).toBeInTheDocument();
  expect(screen.getByText("Analysing role")).toBeInTheDocument();
  expect(screen.getByRole("progressbar", { name: "strategy_snapshot progress" })).toHaveAttribute("aria-valuenow", "40");
  expect(screen.getByText("Operation failed")).toBeInTheDocument();

  fireEvent.click(screen.getByRole("button", { name: "Cancel" }));
  await waitFor(() => expect(mockedApi.post).toHaveBeenCalledWith(`/operations/${operation.id}/cancel`));

  const markRead = screen.getByRole("button", { name: "Mark read" });
  await waitFor(() => expect(markRead).toBeEnabled());
  fireEvent.click(markRead);
  await waitFor(() => expect(mockedApi.post).toHaveBeenCalledWith(`/notifications/${notification.id}/read`));

  const dismiss = screen.getByRole("button", { name: "Dismiss" });
  await waitFor(() => expect(dismiss).toBeEnabled());
  fireEvent.click(dismiss);
  await waitFor(() => expect(mockedApi.delete).toHaveBeenCalledWith(`/notifications/${notification.id}`));
});

test("shows honest empty and failure states", async () => {
  mockedApi.get.mockResolvedValueOnce({ data: [] } as any).mockResolvedValueOnce({ data: [] } as any);
  const { unmount } = renderPage();
  expect(await screen.findByText("No notifications.")).toBeInTheDocument();
  expect(screen.getByText("No background operations yet.")).toBeInTheDocument();
  unmount();

  mockedApi.get.mockRejectedValue(new Error("offline"));
  renderPage();
  expect(await screen.findByRole("alert")).toHaveTextContent("Operations could not be loaded.");
});

test("localizes operation controls and empty states in Norwegian Bokmål", async () => {
  window.localStorage.setItem("uiLanguage", "nb");
  mockedApi.get.mockResolvedValue({ data: [] } as any);

  renderPage();

  expect(await screen.findByText("Ingen varsler.")).toBeInTheDocument();
  expect(screen.getByText("Ingen bakgrunnsoperasjoner ennå.")).toBeInTheDocument();
  expect(screen.getByRole("button", { name: "Oppdater" })).toBeInTheDocument();
});
