import { describe, it, expect, afterEach } from 'vitest';
import { cleanup, render } from 'vitest-browser-svelte';
import { tick } from 'svelte';
import * as m from '$lib/paraglide/messages.js';
import LetterCard from './LetterCard.svelte';
import YearLetterStrip from './YearLetterStrip.svelte';
import { timelineDateLabel } from './dateLabel';
import { makeEntry } from './test-factories';

afterEach(() => cleanup());

const DOC_ID = '22222222-2222-2222-2222-222222222222';

describe('LetterCard', () => {
	it('renders sender, receiver, and title', () => {
		render(LetterCard, {
			entry: makeEntry({ senderName: 'Karl', receiverName: 'Elfriede', title: 'Feldpost' })
		});
		expect(document.body.textContent).toContain('Karl');
		expect(document.body.textContent).toContain('Elfriede');
		expect(document.body.textContent).toContain('Feldpost');
	});

	it('renders the precision date exactly as timelineDateLabel returns (REQ-013)', () => {
		const entry = makeEntry({ eventDate: '1915-06-15', precision: 'MONTH' });
		const expected = timelineDateLabel(entry.eventDate, entry.precision, entry.eventDateEnd);
		expect(expected).toBeTruthy();
		render(LetterCard, { entry });
		expect(document.body.textContent).toContain(expected as string);
	});

	it('renders no date chip when timelineDateLabel returns null (REQ-013)', () => {
		const entry = makeEntry({ precision: 'UNKNOWN', eventDate: undefined });
		render(LetterCard, { entry });
		const chip = document.querySelector('[data-testid="letter-date"]');
		expect(chip).toBeNull();
	});

	it('shows "Unbekannt" for an empty sender, never a bare arrow (REQ-014)', () => {
		render(LetterCard, { entry: makeEntry({ senderName: '', receiverName: 'Elfriede' }) });
		expect(document.body.textContent).toContain('Unbekannt');
	});

	it('shows "Unbekannt" for an empty receiver (REQ-014)', () => {
		render(LetterCard, { entry: makeEntry({ senderName: 'Karl', receiverName: '' }) });
		expect(document.body.textContent).toContain('Unbekannt');
	});

	it('links to exactly /documents/{documentId} with no target (REQ-023)', () => {
		render(LetterCard, { entry: makeEntry({ documentId: DOC_ID }) });
		const link = document.querySelector('a') as HTMLAnchorElement;
		expect(link.getAttribute('href')).toBe(`/documents/${DOC_ID}`);
		expect(link.hasAttribute('target')).toBe(false);
	});

	it('has a touch target of at least 44px (REQ-020)', () => {
		render(LetterCard, { entry: makeEntry() });
		const link = document.querySelector('a') as HTMLAnchorElement;
		expect(link.getBoundingClientRect().height).toBeGreaterThanOrEqual(44);
	});

	it('prefixes a present title with an aria-hidden ✉ and an sr-only "Brief" label (REQ-008)', () => {
		render(LetterCard, { entry: makeEntry({ title: 'Brief aus Stettin', documentId: DOC_ID }) });
		const hidden = document.querySelector('[aria-hidden="true"]');
		expect(hidden?.textContent).toContain('✉');
		const srOnly = document.querySelector('.sr-only');
		expect(srOnly?.textContent).toBe(m.timeline_letter_glyph_label());
		// The glyph is decorative chrome — the document link is unchanged.
		const link = document.querySelector('a') as HTMLAnchorElement;
		expect(link.getAttribute('href')).toBe(`/documents/${DOC_ID}`);
	});

	it('renders no ✉ glyph and no "Brief" label when the title is empty (REQ-016)', () => {
		render(LetterCard, {
			entry: makeEntry({ title: '', senderName: 'Karl', receiverName: 'Elfriede' })
		});
		expect(document.body.textContent).not.toContain('✉');
		expect(document.querySelector('.sr-only')).toBeNull();
		// The row still shows sender → receiver and the date.
		expect(document.body.textContent).toContain('Karl');
		expect(document.body.textContent).toContain('Elfriede');
		expect(document.querySelector('[data-testid="letter-date"]')).not.toBeNull();
	});

	it('renders an HTML-bearing title verbatim as text, never as markup (security, REQ-021)', () => {
		const evil = '<script>alert(1)</script>';
		render(LetterCard, { entry: makeEntry({ title: evil }) });
		expect(document.body.textContent).toContain(evil);
		expect(document.querySelector('a script')).toBeNull();
	});

	it('renders one root-tag chip beneath the meta line when rootTagName is present (REQ-008)', () => {
		render(LetterCard, { entry: makeEntry({ rootTagName: 'Familie', rootTagColor: 'sage' }) });
		const chips = document.querySelectorAll('[data-testid="tag-chip"]');
		expect(chips).toHaveLength(1);
		expect(chips[0].textContent).toContain('Familie');
	});

	it('renders no chip when the letter has no root tag (REQ-005/006)', () => {
		render(LetterCard, { entry: makeEntry({ rootTagName: undefined, rootTagColor: undefined }) });
		expect(document.querySelector('[data-testid="tag-chip"]')).toBeNull();
	});

	it('keeps a long tag name from overflowing the card at 320px, full name in the title (REQ-008a)', () => {
		document.body.style.width = '320px';
		render(LetterCard, {
			entry: makeEntry({
				rootTagName: 'Briefe von der Front und aus der Heimat',
				rootTagColor: 'sienna'
			})
		});
		const link = document.querySelector('a') as HTMLAnchorElement;
		expect(link.scrollWidth).toBeLessThanOrEqual(link.clientWidth);
		const chip = document.querySelector('[data-testid="tag-chip"]') as HTMLElement;
		expect(chip.getAttribute('title')).toBe('Briefe von der Front und aus der Heimat');
		document.body.style.width = '';
	});

	it('renders the chip inside an expanded YearLetterStrip too (REQ-012)', async () => {
		render(YearLetterStrip, {
			letters: [makeEntry({ rootTagName: 'Familie', rootTagColor: 'sage', documentId: 'doc-1' })],
			year: 1909
		});
		(document.querySelector('[data-testid="strip-expand"]') as HTMLButtonElement).click();
		await tick();
		const chip = document.querySelector('[data-testid="tag-chip"]');
		expect(chip?.textContent).toContain('Familie');
	});
});

describe('LetterCard — event-cluster variants (#850, REQ-002)', () => {
	it('carries the .lcard.ev class in the event variant (REQ-002)', () => {
		render(LetterCard, { entry: makeEntry(), variant: 'event' });
		expect(document.querySelector('a.lcard.ev')).not.toBeNull();
	});

	it('is a plain card with no .ev marker by default (REQ-006)', () => {
		render(LetterCard, { entry: makeEntry() });
		expect(document.querySelector('a.ev')).toBeNull();
	});

	it('suppresses the per-letter tag chip when asked, even with a root tag', () => {
		render(LetterCard, {
			entry: makeEntry({ rootTagName: 'Krieg', rootTagColor: 'sienna' }),
			suppressTagChip: true
		});
		expect(document.querySelector('[data-testid="tag-chip"]')).toBeNull();
	});

	it('still shows the per-letter tag chip when not suppressed', () => {
		render(LetterCard, { entry: makeEntry({ rootTagName: 'Krieg', rootTagColor: 'sienna' }) });
		expect(document.querySelector('[data-testid="tag-chip"]')).not.toBeNull();
	});

	it('drops the redundant date line in the compact variant when a title is present (#850)', () => {
		// Inside an event card the year already frames the time, and these archive titles
		// embed the date — so the compact in-card letter omits the date chip.
		render(LetterCard, { entry: makeEntry({ title: 'H-0023 – 6. Juli 1916' }), compact: true });
		expect(document.querySelector('[data-testid="letter-date"]')).toBeNull();
		expect(document.body.textContent).toContain('Karl Raddatz'); // sender still shown
	});

	it('keeps the date in the compact variant when the letter has no title (#850)', () => {
		render(LetterCard, { entry: makeEntry({ title: undefined }), compact: true });
		expect(document.querySelector('[data-testid="letter-date"]')).not.toBeNull();
	});

	it('renders the compact variant on a single tighter row (#850)', () => {
		render(LetterCard, { entry: makeEntry(), compact: true });
		expect(document.querySelector('a.lcard.compact')).not.toBeNull();
	});
});
