import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { page } from 'vitest/browser';
import PersonCard from './PersonCard.svelte';
import type { components } from '$lib/generated/api';

type Person = components['schemas']['PersonSummaryDTO'];

const makePerson = (overrides: Partial<Person> = {}): Person => ({
	id: 'p-1',
	firstName: 'Anna',
	lastName: 'Schmidt',
	displayName: 'Anna Schmidt',
	personType: 'PERSON',
	familyMember: false,
	provisional: false,
	documentCount: 0,
	...overrides
});

afterEach(cleanup);

describe('PersonCard — confirmed person', () => {
	it('renders the display name', async () => {
		render(PersonCard, { props: { person: makePerson() } });
		await expect.element(page.getByText('Anna Schmidt')).toBeVisible();
	});

	it('does not show an unconfirmed badge for a confirmed person', async () => {
		render(PersonCard, { props: { person: makePerson() } });
		await expect.element(page.getByText('unbestätigt')).not.toBeInTheDocument();
	});

	// PersonSummaryDTO intentionally stays year-shaped (ADR-039): the list shows
	// year precision only; full dates live on the detail page.
	it('renders the year-only life-date range', async () => {
		render(PersonCard, { props: { person: makePerson({ birthYear: 1899, deathYear: 1972 }) } });
		await expect.element(page.getByText(/1899/)).toBeVisible();
		await expect.element(page.getByText(/1972/)).toBeVisible();
	});

	it('renders birth-only without dash and wraps glyphs in aria-hidden spans', async () => {
		const { container } = render(PersonCard, {
			props: { person: makePerson({ birthYear: 1899 }) }
		});
		await expect.element(page.getByText(/1899/)).toBeVisible();
		expect(container.textContent).not.toContain('–');
		expect(container.textContent).not.toContain('†');
		const hidden = [...container.querySelectorAll('span[aria-hidden="true"]')].map((el) =>
			el.textContent?.trim()
		);
		expect(hidden).toContain('*');
	});
});

describe('PersonCard — unconfirmed badge keys off provisional only (badge ⇔ count ⇔ triage parity)', () => {
	it('renders without throwing when lastName is null', async () => {
		// Before the fix, `lastName[0]` threw at render for a null lastName. Empty-name
		// crash-safety is a SEPARATE concern from the badge: the placeholder glyph renders
		// regardless, but the "unbestätigt" badge only fires when provisional is true.
		const person = makePerson({
			lastName: null as unknown as string,
			displayName: '?',
			provisional: true
		});
		render(PersonCard, { props: { person } });
		// No throw + provisional → the badge is shown.
		await expect.element(page.getByText('unbestätigt')).toBeVisible();
	});

	it('shows an unbestätigt badge for a provisional person', async () => {
		render(PersonCard, { props: { person: makePerson({ provisional: true }) } });
		await expect.element(page.getByText('unbestätigt')).toBeVisible();
	});

	it('does NOT show the badge for a "?" name when not provisional', async () => {
		// Empty/"?" name alone is no longer treated as unconfirmed — only `provisional` is.
		// This keeps the badge in lockstep with needsReviewCount and the /persons/review list.
		render(PersonCard, {
			props: {
				person: makePerson({ firstName: undefined, lastName: '?', displayName: '?' })
			}
		});
		await expect.element(page.getByText('unbestätigt')).not.toBeInTheDocument();
	});

	it('does NOT show the badge for an UNKNOWN type when not provisional', async () => {
		render(PersonCard, {
			props: { person: makePerson({ personType: 'UNKNOWN', displayName: 'Unklar' }) }
		});
		await expect.element(page.getByText('unbestätigt')).not.toBeInTheDocument();
	});

	it('renders the placeholder glyph (never a "?" initial) for an empty name even without provisional', async () => {
		// Crash-safety branch: a null/empty lastName must not throw and must not show "?".
		render(PersonCard, {
			props: {
				person: makePerson({
					firstName: undefined,
					lastName: null as unknown as string,
					displayName: 'Unbekannt'
				})
			}
		});
		await expect.element(page.getByText('Unbekannt')).toBeVisible();
		await expect.element(page.getByText('unbestätigt')).not.toBeInTheDocument();
	});
});
