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

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

  test.beforeEach(async ({ page }) => {
    page.on("dialog", async (dialog) => {
      await dialog.accept();
    });
    await seedAuth(page);
  });

  test("tenant isolation: forbidden client shows blocked error", async ({
    page,
  }) => {
    const state = {
      clients: [makeClient("tenant-a-client", { name: "Tenant A app" })],
      consents: [] as Consent[],
      auditLogsByCursor: undefined,
    };
    await installDevApiMock(page, state);

    await page.goto("/clients/tenant-b-client");
    await expect(
      page.getByText(
        /Error loading (app|client)|앱 정보를 불러오지 못했습니다|클라이언트 정보를 불러오지 못했습니다/i,
      ),
    ).toBeVisible();
  });

  test("RBAC: user without manage_all permission should not see private apps", async ({
    page,
  }) => {
    const state = {
      clients: [
        makeClient("pkce-client", {
          name: "PKCE only app",
          type: "pkce",
        }),
      ],
      consents: [] as Consent[],
      auditLogsByCursor: undefined,
    };
    await installDevApiMock(page, state);

    await page.goto("/clients");
    await expect(page.getByText("PKCE only app")).toBeVisible();
    await expect(page.getByText("Server side App")).not.toBeVisible();
  });

  test("tenant_member user can enter DevFront and sees empty RP list", async ({
    page,
  }) => {
    await seedAuth(page, "tenant_member");
    const state = {
      clients: [] as ReturnType<typeof makeClient>[],
      consents: [] as Consent[],
      auditLogsByCursor: undefined,
    };
    await installDevApiMock(page, state);

    await page.goto("/clients");
    await expect(page).toHaveURL(/\/clients$/);
    await expect(
      page.getByText(/조회 가능한 RP가 없습니다|No RPs are available/i),
    ).toBeVisible();
    await expect(
      page.getByRole("button", { name: /연동 앱 추가|새 클라이언트|Create/i }),
    ).not.toBeVisible();
  });

  test("rp_admin receives 403 on clients list and sees ForbiddenMessage", async ({
    page,
  }) => {
    await seedAuth(page, "rp_admin");

    const state = {
      clients: [] as ReturnType<typeof makeClient>[],
      consents: [] as Consent[],
      auditLogsByCursor: undefined,
    };
    await installDevApiMock(page, state);

    await page.route("**/api/v1/dev/clients", async (route) => {
      if (route.request().method() === "GET") {
        return route.fulfill({
          status: 403,
          contentType: "application/json",
          body: '{"error": "forbidden"}',
        });
      }
      return route.fallback();
    });

    await page.goto("/clients");
    await expect(
      page.getByText(/RP 관리자는|RP administrators can only access/i),
    ).toBeVisible();
  });

  test("tenant_admin receives 403 on audit logs and sees ForbiddenMessage", async ({
    page,
  }) => {
    await seedAuth(page, "tenant_admin");

    const state = {
      clients: [] as ReturnType<typeof makeClient>[],
      consents: [] as Consent[],
      auditLogsByCursor: undefined,
    };
    await installDevApiMock(page, state);

    await page.route("**/api/v1/dev/audit-logs*", async (route) => {
      if (route.request().method() === "GET") {
        return route.fulfill({
          status: 403,
          contentType: "application/json",
          body: '{"error": "forbidden"}',
        });
      }
      return route.fallback();
    });

    await page.goto("/audit-logs");
    await expect(
      page.getByText(/테넌트 관리자 권한|Tenant administrator permissions/i),
    ).toBeVisible();
  });

  test("user sees audit log access CTA when access is blocked", async ({
    page,
  }, testInfo) => {
    await seedAuth(page, "user");

    const state = {
      clients: [] as ReturnType<typeof makeClient>[],
      consents: [] as Consent[],
      auditLogsByCursor: undefined,
      developerRequests: [],
    };
    await installDevApiMock(page, state);

    await page.goto("/audit-logs");
    await expect(
      page.getByRole("heading", { name: /감사 로그|Audit Logs/ }),
    ).toBeVisible();
    await expect(
      page.getByText(
        /감사 로그는 개발자 권한이 있어야 볼 수 있습니다|Audit logs are available only to users with developer access/i,
      ),
    ).toBeVisible();
    const requestBtn = page.getByRole("button", {
      name: /개발자 권한 신청/,
    });
    await expect(requestBtn).toBeVisible();
    await requestBtn.click();
    await expect(page).toHaveURL(/\/developer-requests$/);
    await captureEvidence(page, testInfo, "security-user-audit-request-entry");
  });

  test("user with approved developer request can enter audit logs without CTA", async ({
    page,
  }, testInfo) => {
    await seedAuth(page, "user");

    const state = {
      clients: [] as ReturnType<typeof makeClient>[],
      consents: [] as Consent[],
      auditLogs: [
        {
          event_id: "evt-audit-1",
          timestamp: "2026-05-29T00:00:00.000Z",
          user_id: "playwright-user",
          event_type: "CLIENT_UPDATE",
          status: "success" as const,
          ip_address: "127.0.0.1",
          user_agent: "playwright",
          details: JSON.stringify({
            action: "UPDATE_CLIENT",
            target_id: "tenant-a-client",
            tenant_id: "tenant-a",
          }),
        },
      ],
      auditLogsByCursor: undefined,
      developerRequests: [
        {
          id: "req-approved",
          userId: "playwright-user",
          userName: "Playwright User",
          name: "Playwright User",
          userEmail: "playwright@example.com",
          organization: "Tenant A",
          reason: "Need access",
          status: "approved",
          createdAt: "2026-05-29T00:00:00.000Z",
          updatedAt: "2026-05-29T00:10:00.000Z",
          approvedAt: "2026-05-29T00:10:00.000Z",
        },
      ],
    };
    await installDevApiMock(page, state);

    await page.goto("/audit-logs");
    await expect(page.getByText("UPDATE_CLIENT")).toBeVisible();
    await expect(
      page.getByRole("button", { name: /개발자 권한 신청/ }),
    ).toHaveCount(0);
    await captureEvidence(page, testInfo, "security-user-audit-approved");
  });
});
