import { test, expect } from '@playwright/test';

test.describe('Person list', () => {
	test.beforeEach(async ({ page }) => {
		await page.goto('/persons');
	});

	test('renders the persons list page', async ({ page }) => {
		await expect(page.getByRole('heading', { name: /Personen/i })).toBeVisible();
		await expect(page.getByRole('link', { name: /Neue Person/i })).toBeVisible();
		await page.screenshot({ path: 'test-results/e2e/persons-list.png' });
	});

	test('search filters the persons list', async ({ page }) => {
		// Navigate directly with the query param — tests that search results are filtered
		// correctly without depending on the debounced oninput → goto chain in CI.
		await page.goto('/persons?q=zzz_unlikely_match');
		await expect(page.getByText(/Keine Personen gefunden/i)).toBeVisible();
		await page.screenshot({ path: 'test-results/e2e/persons-search-empty.png' });
	});

	test('clicking a person opens the detail page', async ({ page }) => {
		const firstPerson = page.locator('a[href^="/persons/"]').first();
		await firstPerson.click();
		await expect(page).toHaveURL(/\/persons\/.+/);
		await page.screenshot({ path: 'test-results/e2e/person-detail.png' });
	});
});

test.describe('Person detail', () => {
	test('shows the person name and their documents', async ({ page }) => {
		await page.goto('/persons');
		const firstPerson = page.locator('a[href^="/persons/"]').first();
		await firstPerson.click();
		// The detail page shows the person's name as the top-level heading
		await expect(page.getByRole('heading', { level: 1 })).toBeVisible();
		await page.screenshot({ path: 'test-results/e2e/person-detail-documents.png' });
	});

	test('can enter and cancel edit mode', async ({ page }) => {
		await page.goto('/persons');
		const firstPerson = page.locator('a[href^="/persons/"]').first();
		await firstPerson.click();
		// Click the edit button
		const editBtn = page.getByRole('button', { name: /Bearbeiten/i });
		if (await editBtn.isVisible()) {
			await editBtn.click();
			await expect(page.getByLabel('Vorname')).toBeVisible();
			await page.screenshot({ path: 'test-results/e2e/person-edit-form.png' });
			// Cancel
			await page.getByRole('button', { name: /Abbrechen/i }).click();
			await expect(page.getByLabel('Vorname')).not.toBeVisible();
		}
	});

	test('birth and death year fields appear in edit mode and save correctly', async ({ page }) => {
		await page.goto('/persons');
		const firstPerson = page.locator('a[href^="/persons/"]:not([href="/persons/new"])').first();
		await firstPerson.click();
		await page.waitForSelector('[data-hydrated]');

		const editBtn = page.getByRole('button', { name: /Bearbeiten/i });
		await editBtn.click();

		await expect(page.getByLabel(/Geburtsjahr/i)).toBeVisible();
		await expect(page.getByLabel(/Todesjahr/i)).toBeVisible();

		await page.getByLabel(/Geburtsjahr/i).fill('1890');
		await page.getByLabel(/Todesjahr/i).fill('1965');

		await page.getByRole('button', { name: /Speichern/i }).click();

		// After saving, the years should be shown in view mode
		await expect(page.getByText('* 1890')).toBeVisible();
		await expect(page.getByText('† 1965')).toBeVisible();
		await page.screenshot({ path: 'test-results/e2e/person-birth-death-years.png' });
	});
});

test.describe('New person', () => {
	test('renders the new person form', async ({ page }) => {
		await page.goto('/persons/new');
		await expect(page.getByLabel('Vorname')).toBeVisible();
		await expect(page.getByLabel('Nachname')).toBeVisible();
		await expect(page.getByRole('button', { name: /Erstellen/i })).toBeVisible();
		await page.screenshot({ path: 'test-results/e2e/person-new.png' });
	});

	test('shows a validation error when submitting with empty fields', async ({ page }) => {
		await page.goto('/persons/new');
		// HTML required attribute prevents submission without filling required fields
		await page.getByRole('button', { name: /Erstellen/i }).click();
		// The form should not have navigated away
		await expect(page).toHaveURL('/persons/new');
	});
});

test.describe('Person creation', () => {
	test('user fills in first and last name and lands on the new person detail page', async ({
		page
	}) => {
		await page.goto('/persons/new');
		await page.getByLabel('Vorname').fill('E2E');
		await page.getByLabel('Nachname').fill('Testperson');
		await page.getByRole('button', { name: /Erstellen/i }).click();

		await expect(page).toHaveURL(/\/persons\/[^/]+$/);
		await expect(page.getByRole('heading', { name: 'E2E Testperson' })).toBeVisible();
		await page.screenshot({ path: 'test-results/e2e/person-create.png' });
	});
});

test.describe('Person detail — sort toggle', () => {
	test('each section has its own sort toggle that works independently', async ({ page }) => {
		await page.goto('/persons');
		const firstPerson = page.locator('a[href^="/persons/"]').first();
		await firstPerson.click();
		await page.waitForSelector('[data-hydrated]');

		// Find sort buttons — there may be 0, 1 or 2 depending on whether sections have >1 doc
		const sortBtns = page.getByRole('button', { name: /Neueste zuerst|Älteste zuerst/i });
		const btnCount = await sortBtns.count();

		if (btnCount >= 1) {
			const firstBtn = sortBtns.first();
			await expect(firstBtn).toContainText('Neueste zuerst');
			await firstBtn.click();
			await expect(firstBtn).toContainText('Älteste zuerst');
			await firstBtn.click();
			await expect(firstBtn).toContainText('Neueste zuerst');
		}

		if (btnCount >= 2) {
			// Second sort button toggles independently
			const secondBtn = sortBtns.nth(1);
			await expect(secondBtn).toContainText('Neueste zuerst');
			await secondBtn.click();
			await expect(secondBtn).toContainText('Älteste zuerst');
			// First button should be unaffected
			await expect(sortBtns.first()).toContainText('Neueste zuerst');
		}

		await page.screenshot({ path: 'test-results/e2e/person-sort-toggle.png' });
	});
});

test.describe('Person detail — sent and received documents', () => {
	test('shows both sent and received document sections', async ({ page }) => {
		await page.goto('/persons');
		const firstPerson = page.locator('a[href^="/persons/"]:not([href="/persons/new"])').first();
		await firstPerson.click();
		await page.waitForSelector('[data-hydrated]');

		await expect(page.getByRole('heading', { name: /Gesendete Dokumente/i })).toBeVisible();
		await expect(page.getByRole('heading', { name: /Empfangene Dokumente/i })).toBeVisible();
		await page.screenshot({ path: 'test-results/e2e/person-sent-received.png' });
	});

	test('shows year range next to document count when documents have dates', async ({ page }) => {
		// Navigate to the first person who has documents with dates
		await page.goto('/persons');
		const personLinks = page.locator('a[href^="/persons/"]:not([href="/persons/new"])');
		const count = await personLinks.count();

		for (let i = 0; i < count; i++) {
			await page.goto('/persons');
			await personLinks.nth(i).click();
			await page.waitForSelector('[data-hydrated]');

			// Check if either section heading has a year range (4 digits)
			const sentHeading = page.getByRole('heading', { name: /Gesendete Dokumente/i }).locator('..');
			const hasYearRange = await sentHeading.locator('span').filter({ hasText: /\d{4}/ }).count();
			if (hasYearRange > 0) {
				await expect(
					sentHeading.locator('span').filter({ hasText: /\d{4}/ }).first()
				).toBeVisible();
				await page.screenshot({ path: 'test-results/e2e/person-year-range.png' });
				return;
			}
		}
		// If no person has dated documents, the test is a no-op (year range is optional)
	});
});

// ── J5: Add a relationship on the person edit page ────────────────────────
//
// Creates two persons via API, then opens the first person's edit page and
// uses the AddRelationshipForm to link them. Asserts the chip appears.

test.describe('Person relationship — add via edit page (J5)', () => {
	let personAId: string;
	let personBName: string;

	test.beforeAll(async ({ request }) => {
		const stamp = Date.now().toString(36);

		const aRes = await request.post('/api/persons', {
			data: { firstName: 'E2E-Rel-A', lastName: stamp }
		});
		if (!aRes.ok()) throw new Error(`Create person A failed: ${aRes.status()}`);
		const a = await aRes.json();
		personAId = a.id;

		const bRes = await request.post('/api/persons', {
			data: { firstName: 'E2E-Rel-B', lastName: stamp }
		});
		if (!bRes.ok()) throw new Error(`Create person B failed: ${bRes.status()}`);
		const b = await bRes.json();
		personBName = b.displayName ?? `E2E-Rel-B ${stamp}`;
	});

	test('user adds a SPOUSE_OF relationship and sees the chip on the edit page', async ({
		page
	}) => {
		await page.goto(`/persons/${personAId}/edit`);
		await page.waitForSelector('[data-hydrated]');

		// Open the AddRelationshipForm by clicking the "+ Beziehung hinzufügen" button.
		await page.getByRole('button', { name: '+ Beziehung hinzufügen' }).click();

		// Select SPOUSE_OF from the type dropdown.
		await page.selectOption('select[name="relationType"]', 'SPOUSE_OF');

		// Type person B's name in the PersonTypeahead.
		const personInput = page.getByRole('combobox', { name: /Person/i });
		await expect(personInput).toBeVisible({ timeout: 5_000 });
		await personInput.fill('E2E-Rel-B');

		const suggestion = page.getByRole('option').first();
		await expect(suggestion).toBeVisible({ timeout: 5_000 });
		await suggestion.click();

		// Submit the relationship form.
		await page.getByRole('button', { name: 'Hinzufügen' }).click();

		// The relationship chip should appear inside the Beziehungen section.
		const relCard = page
			.locator('div')
			.filter({ has: page.locator('h2', { hasText: 'Beziehungen' }) })
			.first();
		await expect(relCard.locator('a[href^="/persons/"]', { hasText: personBName })).toBeVisible({
			timeout: 8_000
		});
		await page.screenshot({ path: 'test-results/e2e/person-relationship-added.png' });
	});
});
