import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import {
  deleteOrphanUserLoginIDs,
  fetchDataIntegrityReport,
  fetchMe,
  fetchOrySSOTSystemStatus,
  fetchOrphanUserLoginIDs,
  flushIdentityCache,
} from "../../lib/adminApi";
import { expectNoAnonymousFormFields } from "../../test/formFieldDiagnostics";
import { createI18nMock } from "../../test/i18nMock";
import DataIntegrityPage from "./DataIntegrityPage";

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

let currentRole = "super_admin";

const integrityReport = {
  status: "fail",
  checkedAt: "2026-05-14T00:00:00Z",
  summary: {
    totalChecks: 2,
    passed: 1,
    warnings: 0,
    failures: 1,
  },
  sections: [
    {
      key: "tenant_integrity",
      label: "테넌트 정합성",
      status: "fail",
      checks: [
        {
          key: "duplicate_tenant_slugs",
          label: "중복 테넌트 slug",
          description: "active tenant slug의 대소문자 무시 중복을 검사합니다.",
          status: "fail",
          severity: "error",
          count: 1,
        },
      ],
    },
  ],
};

vi.mock("../../lib/adminApi", () => ({
  fetchMe: vi.fn(async () => ({ role: currentRole })),
  fetchDataIntegrityReport: vi.fn(async () => integrityReport),
  fetchOrphanUserLoginIDs: vi.fn(async () => ({
    items: [
      {
        id: "login-id-1",
        userId: "user-1",
        userEmail: "missing@example.com",
        tenantId: "tenant-1",
        tenantSlug: "deleted-tenant",
        fieldKey: "emp_id",
        loginId: "EMP001",
        reasons: ["deleted_tenant"],
      },
    ],
    total: 1,
  })),
  fetchOrySSOTSystemStatus: vi.fn(async () => ({
    userProjection: {
      name: "kratos_users",
      status: "ready",
      ready: true,
      lastSyncedAt: "2026-05-11T03:00:00Z",
      updatedAt: "2026-05-11T03:00:10Z",
      projectedUsers: 152,
    },
    identityCache: {
      status: "ready",
      redisReady: true,
      observedCount: 151,
      keyCount: 153,
      lastRefreshedAt: "2026-05-11T03:00:00Z",
      updatedAt: "2026-05-11T03:00:10Z",
    },
  })),
  flushIdentityCache: vi.fn(async () => ({
    status: "success",
    flushedKeys: 153,
    updatedAt: "2026-05-11T03:02:00Z",
  })),
  deleteOrphanUserLoginIDs: vi.fn(async () => ({
    deletedCount: 1,
    deleted: [
      {
        id: "login-id-1",
        userId: "user-1",
        tenantId: "tenant-1",
        fieldKey: "emp_id",
        loginId: "EMP001",
        reasons: ["deleted_tenant"],
      },
    ],
    skippedIds: [],
  })),
}));

function renderPage() {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  });

  return render(
    <QueryClientProvider client={queryClient}>
      <DataIntegrityPage />
    </QueryClientProvider>,
  );
}

describe("DataIntegrityPage", () => {
  beforeEach(() => {
    currentRole = "super_admin";
    vi.clearAllMocks();
    vi.spyOn(window, "confirm").mockReturnValue(true);
    window.localStorage.setItem("locale", "ko");
  });

  it("renders integrity report for super_admin", async () => {
    renderPage();

    expect(await screen.findByText("데이터 정합성 검증")).toBeInTheDocument();
    expect(
      screen.getByRole("tab", { name: "정합성 검사" }),
    ).toBeInTheDocument();
    expect(
      screen.getByRole("tab", { name: "Ory SSOT 시스템" }),
    ).toBeInTheDocument();
    expect(
      await screen.findByText(
        "정합성 상태를 확인하고 데이터 모델 전반의 검증 결과를 살펴봅니다.",
      ),
    ).toBeInTheDocument();
    expect(await screen.findByText("테넌트 정합성")).toBeInTheDocument();
    expect(screen.getByText("중복 테넌트 slug")).toBeInTheDocument();
    expect(screen.getAllByText("1").length).toBeGreaterThan(0);
    expect(fetchDataIntegrityReport).toHaveBeenCalledTimes(1);
  });

  it("renders Ory SSOT cache management inside data integrity", async () => {
    renderPage();

    fireEvent.click(
      await screen.findByRole("tab", { name: "Ory SSOT 시스템" }),
    );

    expect(
      (await screen.findAllByText("Ory SSOT 시스템")).length,
    ).toBeGreaterThan(0);
    expect(await screen.findByText("Redis identity cache")).toBeInTheDocument();
    expect(screen.getAllByText("준비됨").length).toBeGreaterThan(0);
    expect(screen.getByText("152")).toBeInTheDocument();
    expect(screen.getByText("151")).toBeInTheDocument();

    fireEvent.click(screen.getByRole("button", { name: /Redis cache flush/ }));
    await waitFor(() => {
      expect(flushIdentityCache).toHaveBeenCalledTimes(1);
    });
    expect(fetchOrySSOTSystemStatus).toHaveBeenCalled();
  });

  it("shows orphan login ID targets and deletes selected rows", async () => {
    vi.spyOn(window, "confirm").mockReturnValue(true);
    const { container } = renderPage();

    expect(await screen.findByText("유령 로그인 ID 정리")).toBeInTheDocument();
    expect(await screen.findByText("EMP001")).toBeInTheDocument();
    expect(screen.getByText("삭제된 테넌트")).toBeInTheDocument();
    expectNoAnonymousFormFields(container);
    expect(fetchOrphanUserLoginIDs).toHaveBeenCalledTimes(1);

    fireEvent.click(screen.getByRole("checkbox", { name: "EMP001 선택" }));
    fireEvent.click(screen.getByRole("button", { name: "선택 삭제" }));

    await waitFor(() => {
      expect(deleteOrphanUserLoginIDs).toHaveBeenCalled();
    });
    expect(vi.mocked(deleteOrphanUserLoginIDs).mock.calls[0][0]).toEqual([
      "login-id-1",
    ]);
  });

  it("disables recheck button and shows manual recheck progress", async () => {
    let finishRecheck: (value: typeof integrityReport) => void = () => {};
    const pendingRecheck = new Promise<typeof integrityReport>((resolve) => {
      finishRecheck = resolve;
    });

    renderPage();

    expect(await screen.findByText("중복 테넌트 slug")).toBeInTheDocument();
    vi.mocked(fetchDataIntegrityReport).mockImplementationOnce(
      () => pendingRecheck,
    );

    fireEvent.click(screen.getByRole("button", { name: "다시 검사" }));

    expect(screen.getByRole("button", { name: "검사 중" })).toBeDisabled();
    expect(
      screen.getByText("정합성 검사를 실행 중입니다."),
    ).toBeInTheDocument();

    finishRecheck(integrityReport);

    await waitFor(() => {
      expect(screen.getByRole("button", { name: "다시 검사" })).toBeEnabled();
    });
    expect(screen.getByText("검사가 완료되었습니다.")).toBeInTheDocument();
  });

  it("blocks non-super admins", async () => {
    currentRole = "tenant_admin";

    renderPage();

    expect(await screen.findByText("접근 권한이 없습니다")).toBeInTheDocument();
    expect(fetchMe).toHaveBeenCalled();
    expect(fetchDataIntegrityReport).not.toHaveBeenCalled();
  });

  it("renders localized integrity labels in English", async () => {
    window.localStorage.setItem("locale", "en");
    renderPage();

    expect(await screen.findByText("Data Integrity Check")).toBeInTheDocument();
    expect(
      await screen.findByText(
        "Review integrity status and inspect checks across the admin data model.",
      ),
    ).toBeInTheDocument();
    expect(await screen.findByText("Tenant integrity")).toBeInTheDocument();
    expect(
      await screen.findByText("Duplicate tenant slug"),
    ).toBeInTheDocument();
    expect(
      await screen.findByText(
        "Checks duplicate active tenant slugs using LOWER(TRIM(slug)).",
      ),
    ).toBeInTheDocument();
  });
});
