import { expect, test } from "@playwright/test";
import {
  type AuditLog,
  type Consent,
  type DevAssignableUser,
  installDevApiMock,
  makeClient,
  seedAuth,
} from "./helpers/devfront-fixtures";
import { captureEvidence } from "./helpers/evidence";

test.afterEach(async ({ page }, testInfo) => {
  if (testInfo.status === "passed") {
    await captureEvidence(page, testInfo, testInfo.title);
  }
});

test("clients page loads correctly", async ({ page }) => {
  await seedAuth(page, "super_admin");
  await installDevApiMock(page, {
    clients: [
      makeClient("client-playwright", {
        name: "Playwright Client",
        createdAt: new Date().toISOString(),
        redirectUris: ["http://localhost:5174/callback"],
      }),
    ],
    consents: [] as Consent[],
    auditLogsByCursor: undefined,
  });

  await page.goto("/clients");
  await expect(page).toHaveURL(/\/clients$/);

  // 타이틀 확인
  await expect(page).toHaveTitle(/바론 개발자 서비스/);

  // 페이지 내 주요 텍스트 확인
  await expect(page.getByText("연동 앱 목록")).toBeVisible();
  await expect(
    page.getByText("Total Applications", { exact: true }),
  ).toHaveCount(0);

  // 테이블 헤더 확인
  await expect(
    page.locator("th").filter({ hasText: "애플리케이션" }),
  ).toBeVisible();
  await expect(
    page.locator("th").filter({ hasText: /클라이언트 ID|Client ID/i }),
  ).toBeVisible();
});

test("clients page shows Tenant-limited only for tenant access restricted RP", async ({
  page,
}) => {
  await seedAuth(page, "super_admin");
  await installDevApiMock(page, {
    clients: [
      makeClient("client-limited", {
        name: "Limited RP",
        createdAt: "2026-05-02T00:00:00.000Z",
        metadata: {
          tenant_access_restricted: true,
          allowed_tenants: ["tenant-1"],
        },
      }),
      makeClient("client-open", {
        name: "Open RP",
        createdAt: "2026-05-01T00:00:00.000Z",
        metadata: {
          tenant_access_restricted: false,
          allowed_tenants: [],
        },
      }),
    ],
    consents: [] as Consent[],
    auditLogsByCursor: undefined,
  });

  await page.goto("/clients");

  const limitedRow = page.locator("tbody tr", { hasText: "Limited RP" });
  await expect(limitedRow).toContainText("Tenant-limited");

  const openRow = page.locator("tbody tr", { hasText: "Open RP" });
  await expect(openRow).not.toContainText("Tenant-limited");
  await expect(page.getByText("Tenant-scoped")).toHaveCount(0);
});

test("overview page shows recent RP changes", async ({ page }) => {
  await seedAuth(page, "super_admin");
  await installDevApiMock(page, {
    clients: [
      makeClient("client-recent", {
        name: "Recent RP",
      }),
    ],
    consents: [] as Consent[],
    auditLogs: [
      {
        event_id: "evt-1",
        timestamp: "2026-03-03T09:00:00.000Z",
        user_id: "actor-1",
        event_type: "CLIENT_RELATION_CREATE",
        status: "success",
        ip_address: "127.0.0.1",
        user_agent: "playwright",
        details: JSON.stringify({
          action: "ADD_RELATION",
          target_id: "client-recent",
          relation: "config_editor",
          subject: "User:user-2",
        }),
      },
      {
        event_id: "evt-2",
        timestamp: "2026-03-03T08:59:00.000Z",
        user_id: "actor-2",
        event_type: "CLIENT_ROTATE_SECRET",
        status: "success",
        ip_address: "127.0.0.1",
        user_agent: "playwright",
        details: JSON.stringify({
          action: "ROTATE_SECRET",
          target_id: "client-recent",
        }),
      },
    ] as AuditLog[],
    auditLogsByCursor: undefined,
  });

  await page.goto("/");
  await expect(
    page.getByRole("heading", { name: "최근 변경된 앱" }),
  ).toBeVisible();
  await expect(page.getByText("클라이언트 시크릿 재발급")).toBeVisible();
  await expect(page.getByText("관계 추가")).toBeVisible();
  await expect(
    page.getByRole("link", { name: "Recent RP", exact: true }).first(),
  ).toBeVisible();
});

test("clients page shows only five apps by default and expands with more button", async ({
  page,
}) => {
  await seedAuth(page, "super_admin");
  const clients = Array.from({ length: 6 }, (_, index) =>
    makeClient(`client-${index + 1}`, {
      name: `Preview App ${index + 1}`,
      createdAt: new Date(Date.UTC(2026, 2, 3, 9, 10 - index, 0)).toISOString(),
    }),
  );

  await installDevApiMock(page, {
    clients,
    consents: [] as Consent[],
    auditLogs: [] as AuditLog[],
    auditLogsByCursor: undefined,
  });

  await page.goto("/clients");
  await expect(
    page.getByRole("heading", { name: "연동 앱 목록" }),
  ).toBeVisible();
  await expect(
    page
      .locator("table")
      .first()
      .locator("tbody tr")
      .filter({
        hasText: /Preview App \d/,
      }),
  ).toHaveCount(5);
  await expect(
    page.getByText("Preview App 6", { exact: true }),
  ).not.toBeVisible();

  const moreButton = page.getByRole("button", {
    name: "연동 앱 목록 더보기",
  });
  await expect(moreButton).toBeVisible();
  await expect(moreButton).toHaveCount(1);
  await moreButton.click();

  await expect(
    page
      .locator("table")
      .first()
      .locator("tbody tr")
      .filter({
        hasText: /Preview App \d/,
      }),
  ).toHaveCount(6);
  await expect(page.getByText("Preview App 6", { exact: true })).toBeVisible();
  await expect(
    page.getByRole("button", { name: "연동 앱 목록 더보기" }),
  ).toHaveCount(0);
});

test("overview page shows user-delete relation cleanup in recent changes", async ({
  page,
}) => {
  await seedAuth(page, "super_admin");
  await installDevApiMock(page, {
    clients: [
      makeClient("client-cleanup", {
        name: "Cleanup RP",
      }),
    ],
    consents: [] as Consent[],
    users: [
      {
        id: "cleanup-actor",
        name: "Cleanup Actor",
        email: "cleanup.actor@example.com",
      } satisfies DevAssignableUser,
    ],
    auditLogs: [
      {
        event_id: "evt-cleanup-1",
        timestamp: "2026-03-03T09:00:00.000Z",
        user_id: "cleanup-actor",
        event_type: "CLIENT_RELATION_DELETE",
        status: "success",
        ip_address: "127.0.0.1",
        user_agent: "playwright",
        details: JSON.stringify({
          action: "REMOVE_RELATION",
          target_id: "client-cleanup",
          relation: "config_editor",
          subject: "User:deleted-user",
          before: {
            relation: "config_editor",
            subject: "User:deleted-user",
          },
        }),
      },
    ] as AuditLog[],
    auditLogsByCursor: undefined,
  });

  await page.goto("/");
  await expect(
    page.getByRole("heading", { name: "최근 변경된 앱" }),
  ).toBeVisible();
  await expect(
    page.getByRole("link", { name: "Cleanup RP", exact: true }),
  ).toBeVisible();
  await expect(page.getByText("관계 삭제", { exact: true })).toBeVisible();
  await expect(page.getByText(/관계:\s*config_editor/)).toBeVisible();
  await expect(page.getByText(/주체:\s*User:deleted-user/)).toBeVisible();
  await expect(
    page.getByText("cleanup-actor", { exact: true }).first(),
  ).toBeVisible();
});

test("clients page no longer shows recent changes card", async ({ page }) => {
  await seedAuth(page, "super_admin");
  const clients = Array.from({ length: 6 }, (_, index) =>
    makeClient(`client-${index + 1}`, {
      name: `Recent App ${index + 1}`,
    }),
  );
  const auditLogs = clients.map((client, index) => ({
    event_id: `evt-recent-${index + 1}`,
    timestamp: `2026-03-03T09:${String(10 - index).padStart(2, "0")}:00.000Z`,
    user_id: `actor-${index + 1}`,
    event_type: "CLIENT_CREATE",
    status: "success" as const,
    ip_address: "127.0.0.1",
    user_agent: "playwright",
    details: JSON.stringify({
      action: "CREATE_CLIENT",
      target_id: client.id,
      after: {
        name: client.name,
      },
    }),
  }));

  await installDevApiMock(page, {
    clients,
    consents: [] as Consent[],
    auditLogs: auditLogs as AuditLog[],
    auditLogsByCursor: undefined,
  });

  await page.goto("/clients");
  await expect(
    page.getByRole("heading", { name: "최근 변경된 앱" }),
  ).toHaveCount(0);
  await expect(
    page.getByRole("heading", { name: "연동 앱 목록" }),
  ).toBeVisible();
});
