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

type ClaimScenario = {
  title: string;
  role: "super_admin" | "user";
  tenantName: string;
  userMeTenantId: string;
  userMeCompanyCode: string;
  profileClaims: Record<string, unknown>;
  expectedProfileAssertions: Record<string, unknown>;
  expectTenantsToBeAbsent?: boolean;
};

const claimScenarios: ClaimScenario[] = [
  {
    title: "Server Side App preserves tenant and rp claims",
    role: "super_admin",
    tenantName: "Server Side Tenant",
    userMeTenantId: "tenant-server",
    userMeCompanyCode: "server-hq",
    profileClaims: {
      tenant_id: "tenant-server",
      companyCode: "server-hq",
      profile: {
        names: {
          name: "서버 앱 사용자",
        },
        emails: ["server@example.com"],
      },
      joined_tenants: ["tenant-server", "tenant-ops"],
      tenants: {
        "tenant-server": {
          department: "Platform",
          grade: "Lead",
        },
        "tenant-ops": {
          department: "Operations",
          grade: "Member",
        },
      },
      rp_claims: {
        approvalLevel: "A",
      },
      metadata: {
        rp_custom_claims: {
          "server-app": {
            approvalLevel: "A",
          },
        },
      },
    },
    expectedProfileAssertions: {
      tenant_id: "tenant-server",
      companyCode: "server-hq",
      joined_tenants: ["tenant-server", "tenant-ops"],
      rp_claims: {
        approvalLevel: "A",
      },
    },
  },
  {
    title: "PKCE preserves nested profile claims without tenant map expansion",
    role: "user",
    tenantName: "PKCE Tenant",
    userMeTenantId: "tenant-pkce",
    userMeCompanyCode: "pkce-hq",
    profileClaims: {
      tenant_id: "tenant-pkce",
      companyCode: "pkce-hq",
      profile: {
        names: {
          name: "PKCE 사용자",
        },
        emails: ["pkce@example.com"],
      },
      joined_tenants: ["tenant-pkce"],
      rp_claims: {
        features: ["sso", "claims"],
      },
      metadata: {
        rp_custom_claims: {
          "pkce-app": {
            features: ["sso", "claims"],
          },
        },
      },
    },
    expectedProfileAssertions: {
      tenant_id: "tenant-pkce",
      companyCode: "pkce-hq",
      joined_tenants: ["tenant-pkce"],
      rp_claims: {
        features: ["sso", "claims"],
      },
    },
    expectTenantsToBeAbsent: true,
  },
  {
    title: "Headless login keeps session claims together with rp claims",
    role: "super_admin",
    tenantName: "Headless Tenant",
    userMeTenantId: "tenant-headless",
    userMeCompanyCode: "headless-hq",
    profileClaims: {
      tenant_id: "tenant-headless",
      companyCode: "headless-hq",
      profile: {
        names: {
          name: "헤드리스 사용자",
        },
        emails: ["headless@example.com"],
      },
      joined_tenants: ["tenant-headless", "tenant-support"],
      tenants: {
        "tenant-headless": {
          department: "Automation",
          grade: "Manager",
        },
        "tenant-support": {
          department: "Support",
          grade: "Agent",
        },
      },
      rp_claims: {
        approvalLevel: "B",
        loginMode: "headless",
      },
      sid: "session-headless-1",
      session_id: "session-headless-1",
      metadata: {
        rp_custom_claims: {
          "headless-app": {
            approvalLevel: "B",
            loginMode: "headless",
          },
        },
      },
    },
    expectedProfileAssertions: {
      tenant_id: "tenant-headless",
      companyCode: "headless-hq",
      joined_tenants: ["tenant-headless", "tenant-support"],
      rp_claims: {
        approvalLevel: "B",
        loginMode: "headless",
      },
      sid: "session-headless-1",
      session_id: "session-headless-1",
    },
  },
];

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

  for (const scenario of claimScenarios) {
    test(scenario.title, async ({ page }) => {
      await seedAuth(page, {
        role: scenario.role,
        profile: scenario.profileClaims,
      });

      await installDevApiMock(page, {
        clients: [],
        consents: [],
        auditLogsByCursor: undefined,
        users: [],
        tenants: [
          {
            id: scenario.userMeTenantId,
            name: scenario.tenantName,
            slug: scenario.userMeCompanyCode,
          },
        ],
      });

      await page.route("**/api/v1/user/me", async (route) => {
        await route.fulfill({
          status: 200,
          contentType: "application/json",
          body: JSON.stringify({
            id: "playwright-user",
            loginId: "playwright@example.com",
            email: "playwright@example.com",
            name: "Playwright User",
            phoneNumber: "",
            department: "QA",
            tenantId: "",
            tenantName: "",
            role: scenario.role,
            createdAt: "2026-06-01T00:00:00.000Z",
            updatedAt: "2026-06-01T00:00:00.000Z",
          }),
        });
      });

      await page.goto("/profile");

      await expect(
        page.getByRole("heading", { name: "내 정보" }),
      ).toBeVisible();
      const storedUser = await getPersistedOidcUser(page);
      expect(storedUser).not.toBeNull();
      expect(storedUser?.profile).toMatchObject(
        scenario.expectedProfileAssertions,
      );
      if (scenario.expectTenantsToBeAbsent) {
        expect(storedUser?.profile).not.toHaveProperty("tenants");
      } else {
        expect(storedUser?.profile).toHaveProperty("tenants");
      }
      await expect(
        page.getByText(String(scenario.profileClaims.tenant_id)),
      ).toBeVisible();
      await expect(page.getByText(scenario.userMeCompanyCode)).toBeVisible();
      await page.getByRole("button", { name: "권한 및 역할" }).click();
      await expect(
        page.getByRole("heading", { name: "시스템 역할" }),
      ).toBeVisible();
      await expect(
        page.getByText(
          scenario.role === "super_admin"
            ? /시스템 관리자|Super Admin|SUPER_ADMIN/i
            : /일반 사용자|General User|USER/i,
        ),
      ).toBeVisible();
    });
  }
});
