import { expect, test } from "@playwright/test";

test.describe("Audit Logs Management", () => {
  test.beforeEach(async ({ page }) => {
    page.on("console", (msg) => console.log(`[PAGE] ${msg.text()}`));

    await page.addInitScript(() => {
      const authority = `${window.location.origin}/oidc`;
      const client_id = "adminfront";
      const key = `oidc.user:${authority}:${client_id}`;
      const authData = {
        id_token: "fake-id-token",
        access_token: "fake-token",
        token_type: "Bearer",
        scope: "openid profile email",
        profile: {
          sub: "admin-user",
          name: "Admin",
          email: "admin@test.com",
          role: "super_admin",
        },
        expires_at: Math.floor(Date.now() / 1000) + 36000,
      };
      window.localStorage.setItem(key, JSON.stringify(authData));
      window.localStorage.setItem("admin_session", "fake-token");
      window.localStorage.setItem("locale", "ko");
      window.localStorage.setItem("oidc.state", "dummy");

      (
        window as Window & typeof globalThis & { _IS_TEST_MODE?: boolean }
      )._IS_TEST_MODE = true;
    });

    await page.route("**/oidc/**", async (route) => {
      const url = route.request().url();
      if (url.includes("/.well-known/openid-configuration")) {
        const origin = new URL(url).origin;
        return route.fulfill({
          json: {
            issuer: `${origin}/oidc`,
            authorization_endpoint: `${origin}/oidc/auth`,
            token_endpoint: `${origin}/oidc/token`,
            userinfo_endpoint: `${origin}/oidc/userinfo`,
            jwks_uri: `${origin}/oidc/jwks`,
          },
        });
      }
      const origin = new URL(url).origin;
      await route.fulfill({ json: { issuer: `${origin}/oidc` } });
    });

    await page.route("**/v1/audit*", async (route) => {
      const url = route.request().url();
      const urlObj = new URL(url);
      const cursor = urlObj.searchParams.get("cursor");
      const search = urlObj.searchParams.get("search")?.toLowerCase();
      const status = urlObj.searchParams.get("status");
      const offset = cursor ? 20 : 0;

      let allMockLogs = generateMockLogs(40, 0);
      if (status && status !== "all") {
        allMockLogs = allMockLogs.filter((l) => l.status === status);
      }
      if (search) {
        allMockLogs = allMockLogs.filter(
          (l) =>
            l.user_id.toLowerCase().includes(search) ||
            l.details.toLowerCase().includes(search),
        );
      }

      const paginatedItems = allMockLogs.slice(offset, offset + 20);

      console.log(
        `[mock] Audit logs request: ${url} (offset: ${offset}, search: ${search}, status: ${status}, results: ${paginatedItems.length})`,
      );

      return route.fulfill({
        json: {
          items: paginatedItems,
          next_cursor: allMockLogs.length > offset + 20 ? "fake-cursor" : null,
          total: allMockLogs.length,
        },
        headers: { "Access-Control-Allow-Origin": "*" },
      });
    });

    await page.route("**/user/me", async (route) => {
      return route.fulfill({
        json: {
          id: "admin-user",
          name: "Admin",
          role: "super_admin",
          manageableTenants: [],
        },
        headers: { "Access-Control-Allow-Origin": "*" },
      });
    });
  });

  const generateMockLogs = (count: number, offset = 0) => {
    return Array.from({ length: count }, (_, i) => {
      const id = offset + i;
      return {
        event_id: `evt-${id}`,
        timestamp: new Date(Date.now() - id * 10000).toISOString(),
        user_id: id % 2 === 0 ? "user-even" : "user-odd",
        event_type: "API_REQUEST",
        status: id % 5 === 0 ? "failure" : "success",
        ip_address: "192.168.1.1",
        user_agent: "Playwright",
        details: JSON.stringify({
          action: id % 3 === 0 ? "CREATE_TENANT" : "ROTATE_SECRET",
          method: "POST",
          path: `/v1/admin/tenants`,
        }),
      };
    });
  };

  test("should load initial logs and display correctly", async ({ page }) => {
    console.log("[test] Navigating to /audit-logs");
    await page.goto("/audit-logs");

    // Check header - this should be visible immediately now
    await expect(page.getByText(/감사 로그|Audit Logs/i).first()).toBeVisible({
      timeout: 10000,
    });

    // Ensure we are not stuck in a global loading state (AppLayout)
    await expect(page.locator(".animate-spin")).not.toBeVisible({
      timeout: 10000,
    });

    // Check for audit page specific error
    const errorEl = page.getByTestId("audit-error");
    if (await errorEl.isVisible()) {
      const errorText = await errorEl.innerText();
      throw new Error(`Audit log page showed error: ${errorText}`);
    }

    // Wait for loading to finish
    await expect(page.getByTestId("audit-loading")).not.toBeVisible({
      timeout: 15000,
    });

    // Wait for the table row to appear
    await expect(page.locator("tbody tr")).toHaveCount(20, { timeout: 15000 });

    // Check specific data visible in the row
    await expect(page.locator("tbody")).toContainText("user-even");
    await expect(page.locator("tbody")).toContainText("CREATE_TENANT");
  });

  test("should load more logs on scroll (infinite scroll)", async ({
    page,
  }) => {
    await page.goto("/audit-logs");
    await expect(page.locator(".animate-spin")).not.toBeVisible({
      timeout: 10000,
    });
    await expect(page.getByTestId("audit-loading")).not.toBeVisible({
      timeout: 15000,
    });
    await expect(page.locator("tbody tr")).toHaveCount(20, { timeout: 15000 });

    const loadMoreBtn = page.getByRole("button", {
      name: /더 보기|Load more/i,
    });
    await expect(loadMoreBtn).toBeVisible({ timeout: 10000 });
    await expect(loadMoreBtn).toBeEnabled();

    await loadMoreBtn.click();

    // Wait for the next page to load (should reach 40)
    await expect(page.locator("tbody tr")).toHaveCount(40, { timeout: 15000 });
    await expect(page.locator("tbody")).toContainText("user-even");
  });

  test("should filter logs by Action and User ID locally", async ({ page }) => {
    await page.goto("/audit-logs");
    await expect(page.locator(".animate-spin")).not.toBeVisible({
      timeout: 10000,
    });
    await expect(page.getByTestId("audit-loading")).not.toBeVisible({
      timeout: 15000,
    });
    await expect(page.locator("tbody tr")).toHaveCount(20, { timeout: 15000 });

    // Search by User ID
    const userIdInput = page.getByTestId("audit-search-user-id");
    await userIdInput.fill("user-even");

    // Wait for deferred value to apply
    await expect(page.locator("tbody tr")).toHaveCount(20, { timeout: 15000 });
    await expect(page.locator("tbody")).not.toContainText("user-odd");

    // Clear User ID
    await userIdInput.clear();
    await expect(page.locator("tbody tr")).toHaveCount(20, { timeout: 15000 });

    // Search by Action
    const actionInput = page.getByTestId("audit-search-action");
    await actionInput.fill("ROTATE_SECRET");

    // Check that we see ROTATE_SECRET across all 40 logs (40 - 14 = 26)
    // Wait for the mock to respond and render
    await expect(page.locator("tbody tr")).toHaveCount(20, { timeout: 15000 });
    await expect(page.locator("tbody")).not.toContainText("CREATE_TENANT");
  });

  test("should filter logs by Status", async ({ page }) => {
    await page.goto("/audit-logs");
    await expect(page.locator(".animate-spin")).not.toBeVisible({
      timeout: 10000,
    });
    await expect(page.getByTestId("audit-loading")).not.toBeVisible({
      timeout: 15000,
    });
    await expect(page.locator("tbody tr")).toHaveCount(20, { timeout: 15000 });

    // Select "Failure" status
    await page.getByTestId("audit-filter-status").selectOption("failure");

    // Total 8 failures in 40 logs
    await expect(page.locator("tbody tr")).toHaveCount(8, { timeout: 15000 });

    // Select "Success" status
    await page.getByTestId("audit-filter-status").selectOption("success");

    // Total 32 successes in 40 logs, but page limit is 20
    await expect(page.locator("tbody tr")).toHaveCount(20, { timeout: 15000 });
  });
});
