import { test, expect, devices } from '@playwright/test';
import path from 'path';
import { fileURLToPath } from 'url';
import fs from 'fs';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const PDF_FIXTURE = path.resolve(__dirname, 'fixtures/minimal.pdf');
const STORAGE_STATE = path.resolve(__dirname, '.auth/user.json');

/**
 * E2E for issue #362 — Person @mentions, read-mode rendering + hover card (B20/B21).
 *
 * Strategy:
 *   - Create a document, a Person, and a transcription block whose text contains
 *     `@DisplayName` and whose mentionedPersons sidecar links to that person.
 *   - Open the document in read mode.
 *   - B20: page.hover() on the .person-mention link → hover card mounts.
 *   - B21: with context.setHasTouch(true), page.tap() on the link → navigates
 *          to /persons/{id} without ever showing the hover card.
 */

let docId: string;
let personId: string;
let docHref: string;

test.describe.configure({ mode: 'serial' });

test.describe('Person mention — read mode', () => {
	test.beforeAll(async ({ request }) => {
		const baseURL = process.env.E2E_BASE_URL ?? 'http://localhost:3000';

		// 1. Person we will mention.
		const personRes = await request.post('/api/persons', {
			data: {
				firstName: 'Auguste',
				lastName: 'Raddatz',
				personType: 'PERSON',
				birthYear: 1882,
				deathYear: 1944
			}
		});
		if (!personRes.ok()) throw new Error(`Create person failed: ${personRes.status()}`);
		const person = await personRes.json();
		personId = person.id;

		// 2. Document with a PDF so the transcription panel is mountable.
		// Sara #3: timestamp the title so a previous run that crashed in beforeAll
		// (and therefore skipped afterAll cleanup) cannot collide with this one.
		const uniqueSuffix = Date.now();
		const docRes = await request.post('/api/documents', {
			multipart: {
				title: `E2E Person Mention Read ${uniqueSuffix}`,
				documentDate: '1945-05-08'
			}
		});
		if (!docRes.ok()) throw new Error(`Create document failed: ${docRes.status()}`);
		const doc = await docRes.json();
		docId = doc.id;
		docHref = `${baseURL}/documents/${docId}`;

		await request.put(`/api/documents/${docId}`, {
			multipart: {
				title: doc.title as string,
				documentDate: '1945-05-08',
				file: {
					name: 'minimal.pdf',
					mimeType: 'application/pdf',
					buffer: fs.readFileSync(PDF_FIXTURE)
				}
			}
		});

		// 3. Annotation to anchor the block on the page.
		const annRes = await request.post(`/api/documents/${docId}/annotations`, {
			data: { pageNumber: 1, x: 0.1, y: 0.1, width: 0.5, height: 0.1, color: '#00C7B1' }
		});
		if (!annRes.ok()) throw new Error(`Create annotation failed: ${annRes.status()}`);

		// 4. Block text contains @Auguste Raddatz; sidecar links it to personId.
		const blockRes = await request.post(`/api/documents/${docId}/transcription-blocks`, {
			data: {
				pageNumber: 1,
				x: 0.1,
				y: 0.1,
				width: 0.5,
				height: 0.1,
				text: 'Brief an @Auguste Raddatz vom Mai 1944',
				label: null,
				mentionedPersons: [{ personId, displayName: 'Auguste Raddatz' }]
			}
		});
		if (!blockRes.ok()) throw new Error(`Create block failed: ${blockRes.status()}`);
	});

	test.afterAll(async ({ request }) => {
		if (docId) await request.delete(`/api/documents/${docId}`);
		if (personId) await request.delete(`/api/persons/${personId}`);
	});

	test('renders the @mention as an underlined anchor link to /persons/{id}', async ({ page }) => {
		await page.goto(docHref);
		await page.getByRole('button', { name: 'Transkription' }).click();

		const link = page.locator(`a.person-mention[data-person-id="${personId}"]`).first();
		await expect(link).toBeVisible({ timeout: 5000 });
		await expect(link).toHaveAttribute('href', `/persons/${personId}`);
		// The @ trigger is stripped from the rendered text per spec
		await expect(link).toHaveText('Auguste Raddatz');
	});

	test('B20: desktop hover mounts the hover card with loaded person data', async ({ page }) => {
		await page.goto(docHref);
		await page.getByRole('button', { name: 'Transkription' }).click();

		const link = page.locator(`a.person-mention[data-person-id="${personId}"]`).first();
		await link.hover();

		const card = page.getByTestId('person-hover-card');
		await expect(card).toBeVisible({ timeout: 5000 });
		// Loaded state: person displayName is rendered inside the card
		await expect(page.getByTestId('person-hover-card-name')).toHaveText('Auguste Raddatz');
		// Footer link points to /persons/{id}
		await expect(card.locator(`a[href="/persons/${personId}"]`)).toBeVisible();
	});

	test('B20: hover card unmounts on mouseleave', async ({ page }) => {
		await page.goto(docHref);
		await page.getByRole('button', { name: 'Transkription' }).click();

		const link = page.locator(`a.person-mention[data-person-id="${personId}"]`).first();
		await link.hover();
		await expect(page.getByTestId('person-hover-card')).toBeVisible();

		// Move pointer away
		await page.mouse.move(0, 0);
		await expect(page.getByTestId('person-hover-card')).toBeHidden({ timeout: 2000 });
	});

	test('B21: touch-device tap navigates without showing the hover card', async ({ browser }) => {
		const context = await browser.newContext({
			...devices['Pixel 7'],
			storageState: STORAGE_STATE
		});
		const touchPage = await context.newPage();
		try {
			await touchPage.goto(docHref);
			await touchPage.getByRole('button', { name: 'Transkription' }).click();

			const link = touchPage.locator(`a.person-mention[data-person-id="${personId}"]`).first();
			await expect(link).toBeVisible({ timeout: 5000 });

			// Sara #2: assert no card *before* the tap so the test actually proves
			// the touch device suppression worked, not just that we navigated away.
			await expect(touchPage.getByTestId('person-hover-card')).toHaveCount(0);

			await link.tap();
			// The card never mounted — the tap navigated directly per spec.
			await expect(touchPage).toHaveURL(new RegExp(`/persons/${personId}`));
		} finally {
			await context.close();
		}
	});
});
