import { describe, expect, it, vi } from 'vitest'
import { renderToStaticMarkup } from 'react-dom/server'
import type { ImageLoaderProps } from 'next/image'
import type { Media } from '~/data/schema'

vi.mock('next-intl', () => ({
	useTranslations: () => (key: string) => key,
}))

vi.mock('next/image', () => ({
	default: ({ loader, src, alt, sizes }: {
		loader?: (args: ImageLoaderProps) => string
		src: string
		alt: string
		sizes?: string
	}) => <img src={loader ? loader({ src, width: 960, quality: 75 }) : src} alt={alt} data-sizes={sizes} />,
}))

const { blockRegistry } = await import('~/components/blocks/registry')

const base: Media = {
	id: '0b6f0f4a-1c1f-4a51-9b2f-1d0a41f00001',
	projectId: '0b6f0f4a-1c1f-4a51-9b2f-1d0a41f00009',
	kind: 'image',
	originalFilename: 'schema.png',
	path: 'projekt/bild/original.png',
	mime: 'image/png',
	width: 2000,
	height: 1125,
	byteSize: 12345,
	variants: [
		{ width: 480, format: 'webp', path: 'projekt/bild/w480.webp' },
		{ width: 960, format: 'webp', path: 'projekt/bild/w960.webp' },
	],
	variantError: null,
	alt: 'Ein Schema',
	caption: 'Bildunterschrift',
	uploadedBy: null,
	createdAt: new Date('2026-07-30T07:00:00Z'),
}

function media(...items: Media[]): Map<string, Media> {
	return new Map(items.map(item => [item.id, item]))
}

function render(type: string, data: Record<string, unknown>, items: Map<string, Media>): string {
	const Component = blockRegistry[type]

	if (!Component) {
		throw new Error(`kein Block für ${type}`)
	}

	return renderToStaticMarkup(<Component data={data} media={items} />)
}

describe('Blöcke ohne Medium', () => {
	it('bleibt bei jedem Typ ohne Daten leer statt kaputt', () => {
		for (const type of Object.keys(blockRegistry)) {
			expect(render(type, {}, new Map()), type).toBe('')
		}
	})

	it('verliert kein Bild, wenn die Kennung ins Leere zeigt', () => {
		const missing = { mediaId: base.id, mediaIds: [base.id], beforeMediaId: base.id, afterMediaId: base.id }

		for (const type of ['image', 'gallery', 'before_after', 'video']) {
			expect(render(type, missing, new Map()), type).toBe('')
		}
	})

	it('zeigt den Videoverweis auch ohne Medium', () => {
		const markup = render('video', { url: 'https://example.test/film' }, new Map())

		expect(markup).toContain('https://example.test/film')
	})
})

describe('Blöcke mit Medium', () => {
	it('holt die passende Fassung über den Medienweg', () => {
		const markup = render('image', { mediaId: base.id }, media(base))

		expect(markup).toContain('/api/v1/media/file/projekt/bild/w960.webp')
		expect(markup).toContain('Ein Schema')
	})

	it('nimmt das Original, wenn keine Fassung erzeugt wurde', () => {
		const original: Media = { ...base, variants: [] }
		const markup = render('image', { mediaId: original.id }, media(original))

		expect(markup).toContain('/api/v1/media/file/projekt/bild/original.png')
	})

	it('stellt die Galerie mit Vorschaubildern auf', () => {
		const second: Media = { ...base, id: '0b6f0f4a-1c1f-4a51-9b2f-1d0a41f00002', caption: null }
		const markup = render('gallery', { mediaIds: [base.id, second.id] }, media(base, second))

		expect(markup.match(/<img/g)).toHaveLength(2)
		expect(markup).toContain('position')
	})

	it('vergleicht vorher und nachher mit einem Schieberegler', () => {
		const after: Media = { ...base, id: '0b6f0f4a-1c1f-4a51-9b2f-1d0a41f00003' }
		const markup = render(
			'before_after',
			{ beforeMediaId: base.id, afterMediaId: after.id },
			media(base, after),
		)

		expect(markup).toContain('type="range"')
		expect(markup).toContain('clip-path')
	})

	it('zeigt nur eine Seite, wenn das Gegenstück fehlt', () => {
		const markup = render('before_after', { beforeMediaId: base.id }, media(base))

		expect(markup).not.toContain('type="range"')
		expect(markup).toContain('before')
	})

	it('spielt ein Video als Video aus', () => {
		const film: Media = { ...base, kind: 'video', mime: 'video/mp4', variants: [] }
		const markup = render('video', { mediaId: film.id }, media(film))

		expect(markup).toContain('<video')
		expect(markup).toContain('/api/v1/media/file/projekt/bild/original.png')
	})
})
