import { afterEach, describe, expect, it, vi } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';

vi.mock('$app/navigation', () => ({ goto: vi.fn() }));
vi.mock('$app/state', () => ({ navigating: { to: null } }));

import Page from './+page.svelte';
import type { PageData } from './$types';

afterEach(() => {
	cleanup();
	vi.clearAllMocks();
});

function person(id: string, displayName: string) {
	return {
		id,
		firstName: displayName.split(' ')[0] ?? displayName,
		lastName: displayName.split(' ').slice(1).join(' ') || 'X',
		displayName,
		personType: 'PERSON'
	};
}

function makeData(overrides: Partial<PageData> = {}): PageData {
	return {
		geschichten: [],
		drafts: [],
		personFilters: [],
		documentFilter: null,
		canBlogWrite: false,
		...overrides
	} as unknown as PageData;
}

function makeDocumentFilter(overrides: { id?: string; title?: string | null } = {}): {
	id: string;
	title: string | null;
} {
	return {
		id: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
		title: 'Brief an Oma',
		...overrides
	};
}

describe('geschichten page — multi-person filter chips', () => {
	it('renders one chip per person in personFilters', async () => {
		render(Page, {
			data: makeData({
				personFilters: [person('a', 'Anna A'), person('b', 'Bertha B')] as PageData['personFilters']
			})
		});

		await expect
			.element(page.getByRole('button', { name: /Anna A aus Filter entfernen/ }))
			.toBeVisible();
		await expect
			.element(page.getByRole('button', { name: /Bertha B aus Filter entfernen/ }))
			.toBeVisible();
	});

	it('renders the "All" pill in pressed state when no filters are active', async () => {
		render(Page, { data: makeData() });
		await expect
			.element(page.getByRole('button', { name: 'Alle' }))
			.toHaveAttribute('aria-pressed', 'true');
	});

	it('renders the "All" pill in unpressed state when at least one filter is active', async () => {
		render(Page, {
			data: makeData({
				personFilters: [person('a', 'Anna A')] as PageData['personFilters']
			})
		});
		await expect
			.element(page.getByRole('button', { name: 'Alle' }))
			.toHaveAttribute('aria-pressed', 'false');
	});

	it('clicking × on a chip removes only that person from the URL', async () => {
		const { goto } = await import('$app/navigation');
		vi.mocked(goto).mockClear();

		// Seed window.location so the chip-removal logic builds the new URL deterministically.
		const originalHref = window.location.href;
		window.history.replaceState({}, '', '/geschichten?personId=a&personId=b');

		render(Page, {
			data: makeData({
				personFilters: [person('a', 'Anna A'), person('b', 'Bertha B')] as PageData['personFilters']
			})
		});

		const chipBtn = (await page
			.getByRole('button', { name: /Anna A aus Filter entfernen/ })
			.element()) as HTMLElement;
		chipBtn.click();

		await vi.waitFor(() => expect(goto).toHaveBeenCalledOnce());
		const url = vi.mocked(goto).mock.calls[0][0] as string;
		expect(url).toContain('personId=b');
		expect(url).not.toContain('personId=a');

		window.history.replaceState({}, '', originalHref);
	});

	it('JOURNEY row in the list shows the REISE badge (integration: page passes type through)', async () => {
		render(Page, {
			data: makeData({
				geschichten: [
					{ id: 'g1', title: 'Lesereise Berlin', type: 'JOURNEY' }
				] as PageData['geschichten']
			})
		});

		const badge = document.querySelector('[data-testid="journey-badge"]');
		expect(badge).not.toBeNull();
	});

	it('shows the "+ Person wählen" button even when filters are already active', async () => {
		render(Page, {
			data: makeData({
				personFilters: [person('a', 'Anna A')] as PageData['personFilters']
			})
		});
		await expect.element(page.getByRole('button', { name: /Person wählen/ })).toBeVisible();
	});

	describe('document filter chip', () => {
		it('renders the document chip when documentFilter is set', async () => {
			render(Page, {
				data: makeData({ documentFilter: makeDocumentFilter() as PageData['documentFilter'] })
			});

			await expect.element(page.getByText(/Gefiltert nach Brief/)).toBeVisible();
			await expect.element(page.getByText(/Brief an Oma/)).toBeVisible();
		});

		it('does not render the document chip when documentFilter is null', async () => {
			render(Page, { data: makeData() });

			await expect.element(page.getByText(/Gefiltert nach Brief/)).not.toBeInTheDocument();
		});

		it('clicking the document chip remove button navigates without documentId', async () => {
			const { goto } = await import('$app/navigation');
			vi.mocked(goto).mockClear();

			window.history.replaceState(
				{},
				'',
				'/geschichten?documentId=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
			);

			render(Page, {
				data: makeData({ documentFilter: makeDocumentFilter() as PageData['documentFilter'] })
			});

			const removeBtn = (await page
				.getByRole('button', { name: /Brief an Oma aus Filter entfernen/ })
				.element()) as HTMLElement;
			removeBtn.click();

			await vi.waitFor(() => expect(goto).toHaveBeenCalledOnce());
			const url = vi.mocked(goto).mock.calls[0][0] as string;
			expect(url).not.toContain('documentId');
		});

		it('document chip removal preserves active person filters', async () => {
			const { goto } = await import('$app/navigation');
			vi.mocked(goto).mockClear();

			window.history.replaceState(
				{},
				'',
				'/geschichten?personId=p1&documentId=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
			);

			render(Page, {
				data: makeData({
					personFilters: [person('p1', 'Anna A')] as PageData['personFilters'],
					documentFilter: makeDocumentFilter() as PageData['documentFilter']
				})
			});

			const removeBtn = (await page
				.getByRole('button', { name: /Brief an Oma aus Filter entfernen/ })
				.element()) as HTMLElement;
			removeBtn.click();

			await vi.waitFor(() => expect(goto).toHaveBeenCalledOnce());
			const url = vi.mocked(goto).mock.calls[0][0] as string;
			expect(url).toContain('personId=p1');
			expect(url).not.toContain('documentId');
		});

		it('marks the "All" pill as unpressed when document filter is active', async () => {
			render(Page, {
				data: makeData({ documentFilter: makeDocumentFilter() as PageData['documentFilter'] })
			});

			await expect
				.element(page.getByRole('button', { name: 'Alle' }))
				.toHaveAttribute('aria-pressed', 'false');
		});
	});

	it('removing a person chip preserves an active document filter in the URL', async () => {
		const { goto } = await import('$app/navigation');
		vi.mocked(goto).mockClear();

		window.history.replaceState(
			{},
			'',
			'/geschichten?personId=a&documentId=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
		);

		render(Page, {
			data: makeData({
				personFilters: [person('a', 'Anna A')] as PageData['personFilters'],
				documentFilter: makeDocumentFilter() as PageData['documentFilter']
			})
		});

		const chipBtn = (await page
			.getByRole('button', { name: /Anna A aus Filter entfernen/ })
			.element()) as HTMLElement;
		chipBtn.click();

		await vi.waitFor(() => expect(goto).toHaveBeenCalledOnce());
		const url = vi.mocked(goto).mock.calls[0][0] as string;
		expect(url).not.toContain('personId=a');
		expect(url).toContain('documentId=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee');

		window.history.replaceState({}, '', '/');
	});

	it('clearAll removes both person and document filters from the URL', async () => {
		const { goto } = await import('$app/navigation');
		vi.mocked(goto).mockClear();

		window.history.replaceState(
			{},
			'',
			'/geschichten?personId=a&documentId=aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
		);

		render(Page, {
			data: makeData({
				personFilters: [person('a', 'Anna A')] as PageData['personFilters'],
				documentFilter: makeDocumentFilter() as PageData['documentFilter']
			})
		});

		const allBtn = (await page.getByRole('button', { name: 'Alle' }).element()) as HTMLElement;
		allBtn.click();

		await vi.waitFor(() => expect(goto).toHaveBeenCalledOnce());
		const url = vi.mocked(goto).mock.calls[0][0] as string;
		expect(url).not.toContain('personId');
		expect(url).not.toContain('documentId');

		window.history.replaceState({}, '', '/');
	});

	describe('empty state precedence', () => {
		it('shows geschichten_empty_for_document when only document filter is active', async () => {
			render(Page, {
				data: makeData({
					geschichten: [],
					documentFilter: makeDocumentFilter() as PageData['documentFilter']
				})
			});

			await expect.element(page.getByText('Noch keine Geschichten zu diesem Brief')).toBeVisible();
		});

		it('shows geschichten_empty_for_persons when only person filter is active', async () => {
			render(Page, {
				data: makeData({
					geschichten: [],
					personFilters: [person('a', 'Anna A')] as PageData['personFilters']
				})
			});

			await expect.element(page.getByText(/Keine Geschichten für Anna A gefunden/)).toBeVisible();
		});

		it('shows geschichten_empty_no_filter when no filter is active', async () => {
			render(Page, { data: makeData({ geschichten: [] }) });

			await expect
				.element(page.getByText('Es gibt noch keine veröffentlichten Geschichten.'))
				.toBeVisible();
		});

		it('person-wins: shows persons message when both person and document filters are active', async () => {
			render(Page, {
				data: makeData({
					geschichten: [],
					personFilters: [person('a', 'Anna A')] as PageData['personFilters'],
					documentFilter: makeDocumentFilter() as PageData['documentFilter']
				})
			});

			await expect.element(page.getByText(/Keine Geschichten für Anna A gefunden/)).toBeVisible();
			await expect
				.element(page.getByText('Noch keine Geschichten zu diesem Brief'))
				.not.toBeInTheDocument();
		});

		it('chip renders alongside results (empty state not shown when results exist)', async () => {
			render(Page, {
				data: makeData({
					geschichten: [
						{ id: 'g1', title: 'Lesereise Berlin', type: 'JOURNEY' }
					] as PageData['geschichten'],
					documentFilter: makeDocumentFilter() as PageData['documentFilter']
				})
			});

			await expect.element(page.getByText(/Gefiltert nach Brief/)).toBeVisible();
			await expect.element(page.getByText(/Lesereise Berlin/)).toBeVisible();
			await expect
				.element(page.getByText('Noch keine Geschichten zu diesem Brief'))
				.not.toBeInTheDocument();
		});
	});

	it('renders all filter pills with a 44px touch target (h-11)', async () => {
		render(Page, {
			data: makeData({
				personFilters: [person('a', 'Anna A')] as PageData['personFilters']
			})
		});

		// All three pill variants must use h-11 (44px) per the senior-author touch-target rule
		const all = page.getByRole('button', { name: 'Alle' });
		const chip = page.getByRole('button', { name: /Anna A aus Filter entfernen/ });
		const add = page.getByRole('button', { name: /Person wählen/ });

		const allEl = (await all.element()) as HTMLElement;
		const chipEl = (await chip.element()) as HTMLElement;
		const addEl = (await add.element()) as HTMLElement;

		expect(allEl.className).toContain('h-11');
		expect(chipEl.className).toContain('h-11');
		expect(addEl.className).toContain('h-11');
	});
});

// ─── Entwürfe section ─────────────────────────────────────────────────────────

describe('geschichten page — Entwürfe section', () => {
	const draft = () =>
		({
			id: 'draft-1',
			title: 'Mein Entwurf',
			body: '<p>test</p>',
			type: 'STORY',
			status: 'DRAFT',
			author: { firstName: 'Max', lastName: 'Muster' },
			publishedAt: null
		}) as unknown as PageData['geschichten'][0];

	it('Entwürfe section is hidden when drafts array is empty', async () => {
		render(Page, { data: makeData({ drafts: [] }) });
		const heading = Array.from(document.querySelectorAll('h2')).find(
			(h) => h.textContent?.includes('Entwürfe') || h.textContent?.includes('Drafts')
		);
		expect(heading).toBeUndefined();
	});

	it('Entwürfe section is visible when drafts are present', async () => {
		render(Page, { data: makeData({ drafts: [draft()] as PageData['geschichten'] }) });
		const heading = Array.from(document.querySelectorAll('h2')).find(
			(h) => h.textContent?.includes('Entwürfe') || h.textContent?.includes('Drafts')
		);
		expect(heading).not.toBeUndefined();
	});

	it('renders a row for each draft story', async () => {
		render(Page, { data: makeData({ drafts: [draft()] as PageData['geschichten'] }) });
		const link = document.querySelector('a[href="/geschichten/draft-1"]');
		expect(link).not.toBeNull();
	});

	it('draft row shows the draft badge', async () => {
		render(Page, { data: makeData({ drafts: [draft()] as PageData['geschichten'] }) });
		const badge = document.querySelector('[data-testid="draft-badge"]');
		expect(badge).not.toBeNull();
	});

	it('Veröffentlicht heading is present when the Entwürfe section is visible', async () => {
		render(Page, { data: makeData({ drafts: [draft()] as PageData['geschichten'] }) });
		const heading = Array.from(document.querySelectorAll('h2')).find(
			(h) => h.textContent?.includes('Veröffentlicht') || h.textContent?.includes('Published')
		);
		expect(heading).not.toBeUndefined();
	});

	it('Veröffentlicht heading is absent when there are no drafts', async () => {
		render(Page, { data: makeData({ drafts: [] }) });
		const heading = Array.from(document.querySelectorAll('h2')).find(
			(h) => h.textContent?.includes('Veröffentlicht') || h.textContent?.includes('Published')
		);
		expect(heading).toBeUndefined();
	});
});
