/**
 * Revisions E2E Tests
 *
 * Tests revision history in the content editor.
 * Creates a dedicated collection with revision support because the
 * fixture seed's posts collection doesn't include `supports: ["revisions"]`.
 *
 * Covers:
 *   - Edit creates a new revision
 *   - Revision history panel shows revisions
 *   - Restoring a revision updates content
 */

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

// Regex patterns
const REVISIONS_API_PATTERN = /\/api\/content\/[^/]+\/[^/]+\/revisions/;

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

test.describe("Revisions", () => {
	let collectionSlug: string;
	let postId: string;
	let headers: Record<string, string>;
	let baseUrl: string;

	test.beforeEach(async ({ admin, serverInfo }) => {
		await admin.devBypassAuth();

		baseUrl = serverInfo.baseUrl;
		headers = apiHeaders(serverInfo.token, baseUrl);

		// Create a collection with revision + draft support
		collectionSlug = `rev_test_${Date.now()}`;
		await fetch(`${baseUrl}/_emdash/api/schema/collections`, {
			method: "POST",
			headers,
			body: JSON.stringify({
				slug: collectionSlug,
				label: "Revision Test",
				labelSingular: "Revision Test",
				supports: ["revisions", "drafts"],
			}),
		});

		// Add a title field
		await fetch(`${baseUrl}/_emdash/api/schema/collections/${collectionSlug}/fields`, {
			method: "POST",
			headers,
			body: JSON.stringify({ slug: "title", type: "string", label: "Title", required: true }),
		});

		// Add an excerpt field for multi-field revision diffs
		await fetch(`${baseUrl}/_emdash/api/schema/collections/${collectionSlug}/fields`, {
			method: "POST",
			headers,
			body: JSON.stringify({ slug: "excerpt", type: "text", label: "Excerpt" }),
		});

		// Create and publish a post (publishing creates the first live revision)
		const createRes = await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}`, {
			method: "POST",
			headers,
			body: JSON.stringify({
				data: { title: "Original Title", excerpt: "Original excerpt" },
				slug: "revision-test-post",
			}),
		});
		const createData: any = await createRes.json();
		postId = createData.data?.item?.id ?? createData.data?.id;

		await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}/publish`, {
			method: "POST",
			headers,
			body: JSON.stringify({}),
		});
	});

	test.afterEach(async () => {
		// Clean up test data
		await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}`, {
			method: "DELETE",
			headers,
		}).catch(() => {});
		await fetch(`${baseUrl}/_emdash/api/schema/collections/${collectionSlug}`, {
			method: "DELETE",
			headers,
		}).catch(() => {});
	});

	test("revision history panel is visible for collections with revision support", async ({
		admin,
		page,
	}) => {
		await admin.goToEditContent(collectionSlug, postId);
		await admin.waitForLoading();

		// The title field should have the original value
		await expect(page.locator("#field-title")).toHaveValue("Original Title");

		// The Revisions panel should be visible (collapsed by default)
		const revisionsButton = page.locator("button", { hasText: "Revisions" });
		await expect(revisionsButton).toBeVisible({ timeout: 10000 });
	});

	test("expanding revision history shows existing revisions", async ({ admin, page }) => {
		await admin.goToEditContent(collectionSlug, postId);
		await admin.waitForLoading();

		// Click on the Revisions header to expand
		const revisionsButton = page.locator("button", { hasText: "Revisions" });
		await revisionsButton.click();

		// Wait for revisions to load (API call)
		await page
			.waitForResponse((res) => REVISIONS_API_PATTERN.test(res.url()) && res.status() === 200, {
				timeout: 10000,
			})
			.catch(() => {});

		// Should show at least one revision entry
		// The latest revision has a "Current" badge (a span.badge element)
		const currentBadge = page.locator("span.rounded-full", { hasText: "Current" });
		await expect(currentBadge.first()).toBeVisible({ timeout: 10000 });
	});

	test("editing and saving creates a new revision", async ({ admin, page }) => {
		// Get initial revision count
		const initialRes = await fetch(
			`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}/revisions`,
			{ headers },
		);
		const initialData: any = await initialRes.json();
		const initialCount = initialData.data?.total ?? 0;

		// Navigate to edit
		await admin.goToEditContent(collectionSlug, postId);
		await admin.waitForLoading();

		const titleInput = page.locator("#field-title");
		await expect(titleInput).toHaveValue("Original Title");

		// Wait for any initial autosave to settle
		await page.waitForTimeout(3000);

		// Edit the title -- autosave will fire after debounce
		const contentUrl = `/_emdash/api/content/${collectionSlug}/${postId}`;
		const autosavePut = page.waitForResponse(
			(res) => res.url().includes(contentUrl) && res.request().method() === "PUT",
			{ timeout: 15000 },
		);

		await titleInput.fill("Updated Title for Revision");
		const response = await autosavePut;
		expect(response.status()).toBe(200);

		// Wait for autosave indicator
		await expect(page.locator("text=Saved")).toBeVisible({ timeout: 5000 });

		// Now publish to create a new live revision
		const publishButton = page.getByRole("button", { name: "Publish" });
		if (await publishButton.isVisible({ timeout: 3000 }).catch(() => false)) {
			await publishButton.click();
			await admin.waitForLoading();
		}

		// Check that revision count increased
		const afterRes = await fetch(
			`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}/revisions`,
			{ headers },
		);
		const afterData: any = await afterRes.json();
		const afterCount = afterData.data?.total ?? 0;

		expect(afterCount).toBeGreaterThan(initialCount);
	});

	test("can view a revision's data by clicking on it", async ({ admin, page }) => {
		// Create a second revision by updating via API + publishing
		await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}`, {
			method: "PUT",
			headers,
			body: JSON.stringify({ data: { title: "Second Version", excerpt: "Updated excerpt" } }),
		});
		await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}/publish`, {
			method: "POST",
			headers,
			body: JSON.stringify({}),
		});

		// Navigate to edit
		await admin.goToEditContent(collectionSlug, postId);
		await admin.waitForLoading();

		// Expand revisions panel
		const revisionsButton = page.locator("button", { hasText: "Revisions" });
		await revisionsButton.click();

		// Wait for revisions to load
		await page
			.waitForResponse((res) => REVISIONS_API_PATTERN.test(res.url()) && res.status() === 200, {
				timeout: 10000,
			})
			.catch(() => {});

		// Should see the "Current" badge on the latest revision
		await expect(page.locator("span.rounded-full", { hasText: "Current" }).first()).toBeVisible({
			timeout: 10000,
		});

		// There should be multiple revision items (rounded-md border entries)
		const revisionItems = page.locator(".rounded-md.border.p-3");
		const count = await revisionItems.count();
		expect(count).toBeGreaterThanOrEqual(2);

		// Click on the non-latest (older) revision to view its data
		// The second item (index 1) is the older revision
		const olderRevision = revisionItems.nth(1);
		await olderRevision.locator("button.flex-1.text-left").click();

		// A diff view or snapshot should appear
		// Look for either "Content snapshot" or a diff with field changes
		const snapshotOrDiff = page.locator("text=Content snapshot").or(page.locator("text=change"));
		await expect(snapshotOrDiff.first()).toBeVisible({ timeout: 5000 });
	});

	test("restoring a revision updates the content", async ({ admin, page }) => {
		const originalTitle = "Original Title";

		// Create a second version via API
		await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}`, {
			method: "PUT",
			headers,
			body: JSON.stringify({ data: { title: "Changed Title", excerpt: "Changed excerpt" } }),
		});
		await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}/publish`, {
			method: "POST",
			headers,
			body: JSON.stringify({}),
		});

		// Get revision list to find the older revision's ID
		const revisionsRes = await fetch(
			`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}/revisions`,
			{ headers },
		);
		const revisionsData: any = await revisionsRes.json();
		const revisions = revisionsData.data?.items ?? [];

		// Need at least 2 revisions to restore
		expect(revisions.length).toBeGreaterThanOrEqual(2);

		// The first item (index 0) is the latest, older ones follow
		const olderRevision = revisions[1];
		expect(olderRevision).toBeDefined();

		// Navigate to the editor
		await admin.goToEditContent(collectionSlug, postId);
		await admin.waitForLoading();

		// Verify we have the latest title
		await expect(page.locator("#field-title")).toHaveValue("Changed Title");

		// Expand revisions
		const revisionsButton = page.locator("button", { hasText: "Revisions" });
		await revisionsButton.click();

		// Wait for revisions to load
		await page
			.waitForResponse((res) => REVISIONS_API_PATTERN.test(res.url()) && res.status() === 200, {
				timeout: 10000,
			})
			.catch(() => {});

		// Wait for revision items to render
		const revisionItems = page.locator(".rounded-md.border.p-3");
		await expect(revisionItems.first()).toBeVisible({ timeout: 10000 });

		// Find the restore button on the older revision (not the "Current" one)
		// The restore button uses ArrowCounterClockwise icon and title="Restore this version"
		const restoreButton = page.locator('button[title="Restore this version"]').first();
		await expect(restoreButton).toBeVisible({ timeout: 5000 });

		// Click restore -- this opens a ConfirmDialog
		await restoreButton.click();

		// ConfirmDialog should appear
		const confirmDialog = page.getByRole("dialog", { name: "Restore Revision" });
		await expect(confirmDialog).toBeVisible({ timeout: 5000 });

		// Confirm the restore
		await confirmDialog.getByRole("button", { name: "Restore" }).click();

		// Wait for the restore to complete
		await expect(confirmDialog).not.toBeVisible({ timeout: 10000 });

		// Wait for the page to update with restored content
		await admin.waitForLoading();

		// Verify via API that the content was restored
		const contentRes = await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}`, {
			headers,
		});
		const contentData: any = await contentRes.json();
		const currentTitle = contentData.data?.item?.data?.title ?? contentData.data?.item?.title;

		// The title should be back to the original
		expect(currentTitle).toBe(originalTitle);
	});

	test("restore creates a new revision in the history", async ({ admin: _admin }) => {
		// Create a second version
		await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}`, {
			method: "PUT",
			headers,
			body: JSON.stringify({ data: { title: "Version 2", excerpt: "v2 excerpt" } }),
		});
		await fetch(`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}/publish`, {
			method: "POST",
			headers,
			body: JSON.stringify({}),
		});

		// Get revision count before restore
		const beforeRes = await fetch(
			`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}/revisions`,
			{ headers },
		);
		const beforeData: any = await beforeRes.json();
		const countBefore = beforeData.data?.total ?? 0;
		const revisions = beforeData.data?.items ?? [];

		expect(revisions.length).toBeGreaterThanOrEqual(2);
		const olderRevisionId = revisions[1].id;

		// Restore via API
		const restoreRes = await fetch(
			`${baseUrl}/_emdash/api/revisions/${olderRevisionId}/restore`,
			{
				method: "POST",
				headers,
			},
		);
		expect(restoreRes.status).toBe(200);

		// Get revision count after restore -- should have increased
		const afterRes = await fetch(
			`${baseUrl}/_emdash/api/content/${collectionSlug}/${postId}/revisions`,
			{ headers },
		);
		const afterData: any = await afterRes.json();
		const countAfter = afterData.data?.total ?? 0;

		expect(countAfter).toBeGreaterThan(countBefore);
	});
});
