/**
 * Authentication E2E Tests
 *
 * Tests for authentication features:
 * - Login page UI
 * - Dev bypass authentication
 * - Session persistence
 * - Logout
 * - Protected routes redirect to login
 * - User management (admin only)
 * - Security settings (passkey management)
 *
 * Runs against an isolated fixture with seeded data.
 */

import { test, expect } from "../fixtures";

// Regex patterns
const LOGIN_URL_PATTERN = /\/login/;
const ADMIN_URL_PATTERN = /\/_emdash\/admin\/?$/;
const USERS_URL_PATTERN = /\/users/;
const SECURITY_SETTINGS_URL_PATTERN = /\/settings\/security/;
const LOGIN_OR_ADMIN_URL_PATTERN = /\/(login|admin)/;
const SECURITY_MENUITEM_REGEX = /Security/i;
const ADD_PASSKEY_REGEX = /Add Passkey/i;
const SIGN_HEADING_REGEX = /sign/i;

test.describe("Authentication", () => {
	test.describe("Login Page", () => {
		test("displays login page with passkey button", async ({ admin }) => {
			await admin.goto("/login");

			// Should show login page
			await expect(admin.page.locator("h1")).toContainText("Sign in");

			// Should have passkey login button
			await expect(admin.page.locator('button:has-text("Sign in with Passkey")')).toBeVisible();
		});

		test("signup link is hidden when no allowed domains", async ({ admin }) => {
			await admin.goto("/login");

			// No allowed domains are seeded, so signup should not be visible
			await expect(admin.page.locator('a:has-text("Sign up")')).not.toBeVisible();
		});
	});

	test.describe("Protected Routes", () => {
		test("unauthenticated access redirects to login", async ({ admin }) => {
			// Clear cookies to ensure no session
			await admin.page.context().clearCookies();

			// Try to access dashboard without auth
			await admin.goto("/");

			// Should redirect to login (setup is already done via global-setup)
			await expect(admin.page).toHaveURL(LOGIN_URL_PATTERN);
		});
	});

	test.describe("Dev Bypass Authentication", () => {
		test("dev bypass creates session and allows access", async ({ admin }) => {
			// Use dev bypass to authenticate
			await admin.devBypassAuth();

			// Now navigate to admin
			await admin.goto("/");

			// Should see dashboard shell (sidebar with navigation)
			await admin.waitForShell();

			// Should be on admin URL (not redirected to login)
			await expect(admin.page).toHaveURL(ADMIN_URL_PATTERN);
		});

		test("session persists across page loads", async ({ admin }) => {
			await admin.devBypassAuth();
			await admin.goto("/");
			await admin.waitForShell();

			// Navigate to another page via sidebar link
			await admin.page.click('a:has-text("Users")');
			await admin.waitForShell();

			// Should still be authenticated and see users page
			await expect(admin.page).toHaveURL(USERS_URL_PATTERN);
			await admin.expectPageTitle("Users");
		});
	});

	test.describe("Logout", () => {
		test("logout clears session and redirects to login", async ({ admin }) => {
			// Authenticate first
			await admin.devBypassAuth();
			await admin.goto("/");
			await admin.waitForShell();

			// Call logout via API (POST with required headers)
			await admin.page.evaluate(async () => {
				await fetch("/_emdash/api/auth/logout", {
					method: "POST",
					headers: { "X-EmDash-Request": "1" },
				});
			});

			// Try to access admin again
			await admin.page.goto("/_emdash/admin/");
			await admin.page.waitForURL(LOGIN_OR_ADMIN_URL_PATTERN, { timeout: 10000 });

			// Should redirect to login
			await expect(admin.page).toHaveURL(LOGIN_URL_PATTERN);
		});
	});

	test.describe("User Menu", () => {
		test("shows user menu in header", async ({ admin }) => {
			await admin.devBypassAuth();
			await admin.goto("/");
			await admin.waitForShell();

			// Click the user menu trigger (shows "Dev Admin" text)
			await admin.page.getByText("Dev Admin").click();

			// Should show menu options
			await expect(admin.page.locator("text=Log out")).toBeVisible();
			await expect(admin.page.locator("text=Security Settings")).toBeVisible();
			await expect(admin.page.locator("text=Settings").last()).toBeVisible();
		});

		test("security settings link navigates correctly", async ({ admin }) => {
			await admin.devBypassAuth();
			await admin.goto("/");
			await admin.waitForShell();

			// Open user menu
			await admin.page.getByText("Dev Admin").click();

			// Click security settings (if present in menu)
			const securityLink = admin.page.getByRole("menuitem", { name: SECURITY_MENUITEM_REGEX });
			if (await securityLink.isVisible({ timeout: 2000 }).catch(() => false)) {
				await securityLink.click();
				await expect(admin.page).toHaveURL(SECURITY_SETTINGS_URL_PATTERN);
			}
		});
	});
});

test.describe("User Management", () => {
	test.beforeEach(async ({ admin }) => {
		await admin.devBypassAuth();
	});

	test("users page shows user list", async ({ admin }) => {
		await admin.goto("/users");
		await admin.waitForShell();
		await admin.waitForLoading();

		// Should show users page
		await admin.expectPageTitle("Users");

		// Should show at least the dev user
		await expect(admin.page.locator("text=dev@emdash.local")).toBeVisible();
	});

	test("shows invite user button", async ({ admin }) => {
		await admin.goto("/users");
		await admin.waitForShell();

		// Should have invite button
		await expect(admin.page.locator('button:has-text("Invite User")')).toBeVisible();
	});

	test("invite user modal opens and closes", async ({ admin }) => {
		await admin.goto("/users");
		await admin.waitForShell();

		// Click invite button
		await admin.page.locator('button:has-text("Invite User")').click();

		// Should show modal
		await expect(admin.page.locator('input[type="email"]')).toBeVisible();
		await expect(admin.page.locator('button:has-text("Send Invite")')).toBeVisible();

		// Close modal
		await admin.page.keyboard.press("Escape");

		// Modal should close
		await expect(admin.page.locator('[role="dialog"]')).not.toBeVisible();
	});

	test("can click user to see details", async ({ admin }) => {
		await admin.goto("/users");
		await admin.waitForShell();
		await admin.waitForLoading();

		// Click on user email link
		await admin.page.locator("text=dev@emdash.local").first().click();

		// Should show detail panel with user info
		await expect(admin.page.locator("text=Dev Admin").first()).toBeVisible();
	});
});

test.describe("Security Settings", () => {
	test.beforeEach(async ({ admin }) => {
		await admin.devBypassAuth();
	});

	test("shows security settings page", async ({ admin }) => {
		await admin.goto("/settings/security");
		await admin.waitForShell();
		await admin.waitForLoading();

		await expect(admin.page.locator("text=Passkeys").first()).toBeVisible();
	});

	test("shows add passkey button", async ({ admin }) => {
		await admin.goto("/settings/security");
		await admin.waitForShell();
		await admin.waitForLoading();

		await expect(admin.page.getByRole("button", { name: ADD_PASSKEY_REGEX })).toBeVisible();
	});
});

test.describe("Signup Page", () => {
	test("displays signup page", async ({ admin }) => {
		// Navigate directly (not through admin which has auth)
		await admin.page.goto("/_emdash/admin/signup");

		// Wait for the React app to hydrate and render a heading with sign-related content.
		// The SPA may render the login page if signup is disabled, so accept either.
		await expect(
			admin.page.getByRole("heading", { level: 1, name: SIGN_HEADING_REGEX }),
		).toBeVisible({
			timeout: 15000,
		});
	});
});
