/**
 * Comments Moderation E2E Tests
 *
 * Tests the admin comment moderation inbox at /comments.
 * Seeds comments via the public API, then exercises the moderation UI:
 * page rendering, empty state, comment list, approve, and delete.
 */

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

// Regex patterns (e18e/prefer-static-regex)
const PENDING_EMPTY_PATTERN = /no comments awaiting moderation/i;

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function apiHeaders(token: string) {
	return {
		"Content-Type": "application/json",
		Authorization: `Bearer ${token}`,
		"X-EmDash-Request": "1",
	};
}

/** Seed a comment via the public API and return the response body. */
async function seedComment(
	page: import("@playwright/test").Page,
	baseUrl: string,
	token: string,
	postId: string,
	overrides: { body?: string; authorName?: string; authorEmail?: string } = {},
) {
	const res = await page.request.post(`${baseUrl}/_emdash/api/comments/posts/${postId}`, {
		headers: apiHeaders(token),
		data: {
			body: overrides.body ?? "Test comment from E2E",
			authorName: overrides.authorName ?? "E2E Tester",
			authorEmail: overrides.authorEmail ?? "e2e@test.com",
		},
	});
	return res;
}

/** Delete all comments currently in the admin inbox (best-effort cleanup). */
async function cleanupComments(
	page: import("@playwright/test").Page,
	baseUrl: string,
	token: string,
) {
	const headers = apiHeaders(token);

	for (const status of ["pending", "approved", "spam", "trash"] as const) {
		const res = await page.request.fetch(
			`${baseUrl}/_emdash/api/admin/comments?status=${status}&limit=100`,
			{ headers },
		);
		if (!res.ok()) continue;

		const data: { data?: { items?: { id: string }[] } } = await res.json().catch(() => ({}));
		const ids = data?.data?.items?.map((c) => c.id) ?? [];
		if (ids.length === 0) continue;

		await page.request
			.post(`${baseUrl}/_emdash/api/admin/comments/bulk`, {
				headers,
				data: { ids, action: "delete" },
			})
			.catch(() => {});
	}
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------

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

	test("page renders with correct title", async ({ admin }) => {
		await admin.goto("/comments");
		await admin.waitForShell();
		await admin.waitForLoading();

		await admin.expectPageTitle("Comments");
	});

	test("shows empty state when no comments exist", async ({ admin, page, serverInfo }) => {
		// Clean up any existing comments first
		await cleanupComments(page, serverInfo.baseUrl, serverInfo.token);

		await admin.goto("/comments");
		await admin.waitForShell();
		await admin.waitForLoading();

		// The "Pending" tab is active by default -- should show empty message
		await expect(page.locator("td").filter({ hasText: PENDING_EMPTY_PATTERN })).toBeVisible({
			timeout: 10000,
		});
	});

	test("displays seeded comments with author and body", async ({ admin, page, serverInfo }) => {
		const postId = serverInfo.contentIds.posts[0]!;

		// Clean slate
		await cleanupComments(page, serverInfo.baseUrl, serverInfo.token);

		// Seed two comments
		await seedComment(page, serverInfo.baseUrl, serverInfo.token, postId, {
			body: "First seeded comment",
			authorName: "Alice Commenter",
			authorEmail: "alice@test.com",
		});
		await seedComment(page, serverInfo.baseUrl, serverInfo.token, postId, {
			body: "Second seeded comment",
			authorName: "Bob Commenter",
			authorEmail: "bob@test.com",
		});

		await admin.goto("/comments");
		await admin.waitForShell();
		await admin.waitForLoading();

		// Comments land as "pending" by default (moderation: first_time or all).
		// The Pending tab is the default view, so we should see them.
		// If the collection auto-approves, check the Approved tab instead.
		const approvedTab = page.locator('[role="tab"]', { hasText: "Approved" });

		// Try pending first -- if empty, check approved
		let foundAlice = await page
			.locator("text=Alice Commenter")
			.isVisible({ timeout: 5000 })
			.catch(() => false);

		if (!foundAlice) {
			// Comments may have been auto-approved
			await approvedTab.click();
			await admin.waitForLoading();
			foundAlice = await page
				.locator("text=Alice Commenter")
				.isVisible({ timeout: 5000 })
				.catch(() => false);
		}

		// At least one comment should be visible with author name and body
		expect(foundAlice).toBe(true);
		await expect(page.locator("text=First seeded comment").first()).toBeVisible();
		await expect(page.locator("text=Bob Commenter").first()).toBeVisible();
		await expect(page.locator("text=Second seeded comment").first()).toBeVisible();
	});

	test("approve a pending comment", async ({ admin, page, serverInfo }) => {
		const postId = serverInfo.contentIds.posts[0]!;

		// Clean slate
		await cleanupComments(page, serverInfo.baseUrl, serverInfo.token);

		// Seed a comment
		await seedComment(page, serverInfo.baseUrl, serverInfo.token, postId, {
			body: "Comment to approve",
			authorName: "Approval Tester",
			authorEmail: "approve@test.com",
		});

		await admin.goto("/comments");
		await admin.waitForShell();
		await admin.waitForLoading();

		// Ensure we're on the Pending tab
		const pendingTab = page.locator('[role="tab"]', { hasText: "Pending" });
		await pendingTab.click();
		await admin.waitForLoading();

		// If the comment was auto-approved, this test cannot proceed -- skip gracefully
		const hasPendingComment = await page
			.locator("text=Approval Tester")
			.isVisible({ timeout: 5000 })
			.catch(() => false);

		if (!hasPendingComment) {
			// Comment was auto-approved -- verify it's in the Approved tab instead
			const approvedTab = page.locator('[role="tab"]', { hasText: "Approved" });
			await approvedTab.click();
			await admin.waitForLoading();
			await expect(page.locator("text=Approval Tester").first()).toBeVisible({
				timeout: 5000,
			});
			return;
		}

		// Find the comment row and click the Approve button
		const row = page.locator("tr", { hasText: "Approval Tester" });
		const approveBtn = row.locator('button[aria-label="Approve"]');
		await expect(approveBtn).toBeVisible({ timeout: 5000 });
		await approveBtn.click();

		// Wait for the mutation to settle
		await admin.waitForLoading();

		// The comment should disappear from the Pending tab
		await expect(page.locator("tr", { hasText: "Approval Tester" })).not.toBeVisible({
			timeout: 10000,
		});

		// Verify it moved to the Approved tab
		const approvedTab = page.locator('[role="tab"]', { hasText: "Approved" });
		await approvedTab.click();
		await admin.waitForLoading();

		await expect(page.locator("text=Approval Tester").first()).toBeVisible({
			timeout: 10000,
		});
	});

	test("delete a comment permanently", async ({ admin, page, serverInfo }) => {
		const postId = serverInfo.contentIds.posts[0]!;

		// Clean slate
		await cleanupComments(page, serverInfo.baseUrl, serverInfo.token);

		// Seed a comment
		await seedComment(page, serverInfo.baseUrl, serverInfo.token, postId, {
			body: "Comment to delete",
			authorName: "Delete Tester",
			authorEmail: "delete@test.com",
		});

		await admin.goto("/comments");
		await admin.waitForShell();
		await admin.waitForLoading();

		// Find the comment -- could be in Pending or Approved
		let commentVisible = await page
			.locator("text=Delete Tester")
			.isVisible({ timeout: 5000 })
			.catch(() => false);

		if (!commentVisible) {
			const approvedTab = page.locator('[role="tab"]', { hasText: "Approved" });
			await approvedTab.click();
			await admin.waitForLoading();
			commentVisible = await page
				.locator("text=Delete Tester")
				.isVisible({ timeout: 5000 })
				.catch(() => false);
		}

		expect(commentVisible).toBe(true);

		// The admin user should see the "Delete permanently" button
		const row = page.locator("tr", { hasText: "Delete Tester" });
		const deleteBtn = row.locator('button[aria-label="Delete permanently"]');

		const hasDeleteBtn = await deleteBtn.isVisible({ timeout: 3000 }).catch(() => false);

		if (!hasDeleteBtn) {
			// Fallback: try the "Trash" button instead (non-admin role)
			const trashBtn = row.locator('button[aria-label="Trash"]');
			await expect(trashBtn).toBeVisible({ timeout: 3000 });
			await trashBtn.click();
			await admin.waitForLoading();

			// Comment should disappear from the current tab
			await expect(row).not.toBeVisible({ timeout: 10000 });
			return;
		}

		// Click "Delete permanently" -- this opens a ConfirmDialog
		await deleteBtn.click();

		// Confirm deletion in the dialog
		const dialog = page.locator('[role="dialog"]');
		await expect(dialog).toBeVisible({ timeout: 5000 });
		await expect(dialog.locator("text=Delete Comment")).toBeVisible();

		await dialog.getByRole("button", { name: "Delete" }).click();

		// Wait for dialog to close and comment to disappear
		await expect(dialog).not.toBeVisible({ timeout: 10000 });
		await admin.waitForLoading();

		// Comment should be gone from all tabs
		await expect(page.locator("text=Delete Tester")).not.toBeVisible({ timeout: 10000 });
	});
});
