import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { fireEvent, render, screen } from "@testing-library/react";
import { MemoryRouter, Route, Routes } from "react-router-dom";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createI18nMock } from "../../test/i18nMock";
import AppLayout from "./AppLayout";

const authState = {
  isAuthenticated: true,
  isLoading: false,
  user: {
    access_token: "access-token",
    expires_at: Math.floor(Date.now() / 1000) + 120,
    profile: {
      sub: "admin-1",
      name: "Admin User",
      email: "admin@example.com",
    },
  },
  signinSilent: vi.fn(async () => undefined),
  removeUser: vi.fn(),
};

vi.mock("react-oidc-context", () => ({
  useAuth: () => authState,
}));

vi.mock("../../lib/i18n", () => createI18nMock());

vi.mock("../../lib/adminApi", () => ({
  fetchMe: vi.fn(async () => ({
    id: "admin-1",
    name: "Fetched Admin",
    email: "fetched@example.com",
    role: "super_admin",
    tenantId: "tenant-1",
    manageableTenants: [
      {
        id: "tenant-1",
        name: "GPDTDC",
        slug: "gpdtdc",
        type: "COMPANY",
      },
      {
        id: "tenant-2",
        name: "기술연구팀",
        slug: "gpdtdc-rnd",
        type: "ORGANIZATION",
      },
    ],
  })),
}));

function renderLayout(entry = "/users") {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });

  return render(
    <QueryClientProvider client={queryClient}>
      <MemoryRouter initialEntries={[entry]}>
        <Routes>
          <Route path="/" element={<AppLayout />}>
            <Route path="users" element={<div>Users outlet</div>} />
            <Route path="users/:id" element={<div>User detail outlet</div>} />
            <Route
              path="tenants/:tenantId"
              element={<div>Tenant outlet</div>}
            />
            <Route path="worksmobile" element={<div>Worksmobile outlet</div>} />
            <Route path="login" element={<div>Login outlet</div>} />
          </Route>
        </Routes>
      </MemoryRouter>
    </QueryClientProvider>,
  );
}

describe("admin AppLayout", () => {
  beforeEach(() => {
    (
      window as Window & typeof globalThis & { _IS_TEST_MODE?: boolean }
    )._IS_TEST_MODE = true;
    authState.isAuthenticated = true;
    authState.isLoading = false;
    authState.user.expires_at = Math.floor(Date.now() / 1000) + 120;
    authState.signinSilent.mockClear();
    authState.removeUser.mockClear();
    window.localStorage.clear();
    vi.spyOn(window, "confirm").mockReturnValue(true);
  });

  it("renders admin navigation, fetched profile, and outlet content", async () => {
    renderLayout();

    expect(await screen.findByText("Fetched Admin")).toBeInTheDocument();
    expect(screen.getByText("Admin Control")).toBeInTheDocument();
    expect(screen.getByText("Users outlet")).toBeInTheDocument();
    expect(screen.getByText("Tenants")).toBeInTheDocument();
    expect(screen.getByText("Org Chart")).toBeInTheDocument();
    expect(screen.getByText("Worksmobile")).toBeInTheDocument();
    expect(screen.getByText("User Projection")).toBeInTheDocument();
    expect(screen.getByText("Data Integrity")).toBeInTheDocument();
    const navigation = screen.getByRole("navigation");
    const navLabels = Array.from(navigation.querySelectorAll("a")).map((link) =>
      link.textContent?.trim(),
    );
    expect(navLabels).toEqual([
      "Overview",
      "Tenants",
      "Org Chart",
      "Worksmobile",
      "User Projection",
      "Data Integrity",
      "Users",
      "Auth Guard",
      "API Keys",
      "Audit Logs",
    ]);
    const worksmobileIcon = screen.getByTestId("worksmobile-nav-icon");
    expect(worksmobileIcon.tagName.toLowerCase()).toBe("svg");
    expect(worksmobileIcon).toHaveAttribute("fill", "none");
    expect(worksmobileIcon.querySelectorAll("path")).toHaveLength(4);
    expect(worksmobileIcon.querySelector('path[fill="white"]')).toBeNull();
  });

  it("toggles the sidebar and persists the collapsed state", async () => {
    renderLayout();

    const collapseButton = await screen.findByRole("button", {
      name: "사이드바 접기",
    });
    fireEvent.click(collapseButton);

    expect(window.localStorage.getItem("baron_shell_sidebar_collapsed")).toBe(
      "true",
    );
    expect(
      screen.getByRole("button", { name: "사이드바 펼치기" }),
    ).toBeInTheDocument();
  });

  it("opens profile menu, navigates, toggles theme/session, and logs out", async () => {
    renderLayout();

    const themeButton = await screen.findByRole("button", {
      name: "테마 전환",
    });
    fireEvent.click(themeButton);
    expect(document.documentElement.classList.contains("dark")).toBe(true);

    fireEvent.click(screen.getByRole("button", { name: "계정 메뉴 열기" }));
    expect(screen.getByText("Manageable Tenants")).toBeInTheDocument();

    const sessionSwitch = screen.getByRole("switch");
    fireEvent.click(sessionSwitch);
    expect(window.localStorage.getItem("baron_session_expiry_enabled")).toBe(
      "false",
    );

    fireEvent.click(screen.getByText("기술연구팀"));
    expect(await screen.findByText("Tenant outlet")).toBeInTheDocument();

    fireEvent.click(screen.getByRole("button", { name: "계정 메뉴 열기" }));
    fireEvent.click(screen.getAllByText("내 정보")[0]);
    expect(await screen.findByText("User detail outlet")).toBeInTheDocument();

    fireEvent.click(screen.getByRole("button", { name: "계정 메뉴 열기" }));
    fireEvent.click(screen.getAllByText("Logout")[1]);
    expect(window.confirm).toHaveBeenCalled();
    expect(authState.removeUser).toHaveBeenCalled();
  }, 10_000);

  it("attempts silent renewal on user activity when session is near expiry", async () => {
    authState.user.expires_at = Math.floor(Date.now() / 1000) + 60;

    renderLayout();
    await screen.findByText("Fetched Admin");
    fireEvent.keyDown(window, { key: "Tab" });

    expect(authState.signinSilent).toHaveBeenCalled();
  });
});
