import { test, expect } from "@playwright/test";
import { startServer, type TestServer } from "./helpers";

let server: TestServer;

test.beforeAll(async () => {
	server = await startServer();
	// Seed data so the graph has nodes to render
	server.cli('task create "Graph Test Task 1" -d "First task for graph" --priority high -l "feature"');
	server.cli('task create "Graph Test Task 2" -d "Second task for graph" --priority medium -l "backend"');
	server.cli('doc create "Graph Doc" -d "Documentation for graph tests" -t "test"');
});

test.afterAll(() => {
	server?.cleanup();
});

test.describe("Knowledge Graph", () => {
	test("graph page loads without errors", async ({ page }) => {
		await test.step("Navigate to graph page", async () => {
			await page.goto(`${server.baseURL}/graph`);
		});

		await test.step("Page header/toolbar is visible", async () => {
			// GraphToolbar renders a search input with placeholder "Search graph..."
			await expect(page.getByPlaceholder("Search graph...")).toBeVisible({ timeout: 8000 });
		});

		await test.step("No error state is shown", async () => {
			await expect(page.getByText("Failed to load graph")).not.toBeVisible();
		});
	});

	test("graph canvas container is visible", async ({ page }) => {
		await test.step("Navigate to graph", async () => {
			await page.goto(`${server.baseURL}/graph`);
		});

		await test.step("Graph canvas area exists", async () => {
			// The ForceGraph2D renders inside an absolute positioned container
			const canvas = page.locator("canvas").first();
			await expect(canvas).toBeVisible({ timeout: 8000 });
		});
	});

	test("toolbar shows search and node count", async ({ page }) => {
		await test.step("Navigate to graph", async () => {
			await page.goto(`${server.baseURL}/graph`);
		});

		await test.step("Search input is present", async () => {
			await expect(page.getByPlaceholder("Search graph...")).toBeVisible({ timeout: 8000 });
		});

		await test.step("Node/edge count is shown", async () => {
			// GraphToolbar displays "{n} nodes, {m} edges"
			await expect(page.getByText(/nodes/)).toBeVisible({ timeout: 5000 });
			await expect(page.getByText(/edges/)).toBeVisible({ timeout: 5000 });
		});

		await test.step("Zoom to fit and fullscreen buttons are present", async () => {
			await expect(page.getByTitle("Zoom to fit")).toBeVisible({ timeout: 5000 });
			await expect(page.getByTitle("Toggle fullscreen")).toBeVisible({ timeout: 5000 });
		});
	});

	test("legend shows filter controls for node types", async ({ page }) => {
		await test.step("Navigate to graph", async () => {
			await page.goto(`${server.baseURL}/graph`);
		});

		await test.step("Legend panel is visible", async () => {
			await expect(page.getByText("Node types")).toBeVisible({ timeout: 8000 });
		});

		await test.step("Node type filters are present", async () => {
			await expect(page.getByRole("button", { name: "Tasks" })).toBeVisible({ timeout: 5000 });
			await expect(page.getByRole("button", { name: "Docs" })).toBeVisible({ timeout: 5000 });
			await expect(page.getByRole("button", { name: "Memories" })).toBeVisible({ timeout: 5000 });
		});

		await test.step("Edge section is present", async () => {
			await expect(page.getByText("Edges", { exact: true })).toBeVisible({ timeout: 5000 });
		});
	});

	test("graph nodes exist after creating tasks via CLI", async ({ page }) => {
		await test.step("Create additional task", async () => {
			server.cli('task create "Fresh Graph Task" -d "Created after server start"');
		});

		await test.step("Navigate and refresh graph", async () => {
			await page.goto(`${server.baseURL}/graph`);
		});

		await test.step("Node count shows at least some nodes", async () => {
			// Wait for the graph to load, then check node count text
			const nodeCountText = page.getByText(/0 nodes/);
			await expect(nodeCountText).not.toBeVisible({ timeout: 10000 });

			// Verify the toolbar shows a non-zero node count
			const countRegex = /(\d+)\s*nodes/;
			const countText = page.getByText(countRegex);
			await expect(countText).toBeVisible({ timeout: 5000 });
		});
	});

	test("search in graph toolbar highlights matching nodes", async ({ page }) => {
		await test.step("Navigate to graph", async () => {
			await page.goto(`${server.baseURL}/graph`);
		});

		await test.step("Wait for graph to load", async () => {
			await expect(page.getByText(/nodes/)).toBeVisible({ timeout: 8000 });
		});

		await test.step("Type search query", async () => {
			await page.getByPlaceholder("Search graph...").fill("Graph Test");
			await page.waitForTimeout(500);
		});

		await test.step("Match count is shown", async () => {
			// Toolbar shows "{n} matches" when searching
			await expect(page.getByText(/matches/)).toBeVisible({ timeout: 5000 });
		});

		await test.step("Clearing search removes match indicator", async () => {
			await page.getByPlaceholder("Search graph...").fill("");
			await page.waitForTimeout(300);
			await expect(page.getByText(/matches/)).not.toBeVisible();
		});
	});

	test("node type filter toggles work", async ({ page }) => {
		await test.step("Navigate to graph", async () => {
			await page.goto(`${server.baseURL}/graph`);
		});

		await test.step("Wait for graph to load", async () => {
			await expect(page.getByText(/nodes/)).toBeVisible({ timeout: 8000 });
		});

		await test.step("Click Tasks filter to toggle", async () => {
			await page.getByRole("button", { name: "Tasks" }).click();
			await page.waitForTimeout(300);
		});

		await test.step("Node count may decrease", async () => {
			// The graph should still be visible; node count may have changed
			await expect(page.getByText(/nodes/)).toBeVisible();
		});
	});

	test("detail panel opens when clicking a node", async ({ page }) => {
		await test.step("Navigate to graph", async () => {
			await page.goto(`${server.baseURL}/graph`);
		});

		await test.step("Wait for graph to load", async () => {
			await expect(page.getByText(/nodes/)).toBeVisible({ timeout: 8000 });
		});

		await test.step("Click on canvas area (ForceGraph2D canvas)", async () => {
			const canvas = page.locator("canvas").first();
			if (await canvas.isVisible({ timeout: 5000 })) {
				await canvas.click();
				await page.waitForTimeout(300);
			}
		});

		await test.step("Clicking background clears selection (no crash)", async () => {
			// Clicking the background should clear selection without error
			await expect(page.getByText("Failed to load graph")).not.toBeVisible();
		});
	});

	test("impact summary appears after selecting a node", async ({ page }) => {
		await test.step("Navigate to graph", async () => {
			await page.goto(`${server.baseURL}/graph`);
		});

		await test.step("Wait for graph to load", async () => {
			await expect(page.getByText(/nodes/)).toBeVisible({ timeout: 8000 });
		});

		await test.step("Clicking canvas should not show impact bar initially", async () => {
			// Impact summary only shows when a node is selected and has connections
			// Just verify the page is stable after interaction
			const canvas = page.locator("canvas").first();
			if (await canvas.isVisible({ timeout: 5000 })) {
				await canvas.click();
				await page.waitForTimeout(500);
			}
		});
	});
});
