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

afterEach(() => cleanup());

// ─── Rendering ────────────────────────────────────────────────────────────────

describe('DateInput – rendering', () => {
	it('renders a text input with inputmode=numeric and maxlength=10', async () => {
		render(DateInput, {});
		const input = page.getByRole('textbox');
		await expect.element(input).toBeInTheDocument();
		await expect.element(input).toHaveAttribute('inputmode', 'numeric');
		await expect.element(input).toHaveAttribute('maxlength', '10');
	});

	it('has default placeholder from paraglide', async () => {
		render(DateInput, {});
		const input = page.getByRole('textbox');
		await expect.element(input).toHaveAttribute('placeholder', 'TT.MM.JJJJ');
	});

	it('accepts a custom placeholder', async () => {
		render(DateInput, { placeholder: 'Geburtsdatum' });
		const input = page.getByRole('textbox');
		await expect.element(input).toHaveAttribute('placeholder', 'Geburtsdatum');
	});

	it('passes id prop to the input', async () => {
		render(DateInput, { id: 'my-date' });
		const input = page.getByRole('textbox');
		await expect.element(input).toHaveAttribute('id', 'my-date');
	});
});

// ─── Init from value ──────────────────────────────────────────────────────────

describe('DateInput – init from value', () => {
	it('displays ISO value in German format on mount', async () => {
		render(DateInput, { value: '2024-12-20' });
		const input = page.getByRole('textbox');
		await expect.element(input).toHaveValue('20.12.2024');
	});

	it('starts empty and error-free when no value is given', async () => {
		let errorMessage: string | null = null;
		render(DateInput, {
			get errorMessage() {
				return errorMessage;
			},
			set errorMessage(v) {
				errorMessage = v;
			}
		});
		const input = page.getByRole('textbox');
		await expect.element(input).toHaveValue('');
		expect(errorMessage).toBeNull();
	});
});

// ─── Typing valid date ────────────────────────────────────────────────────────

describe('DateInput – typing a valid date', () => {
	it('auto-formats to DD.MM.YYYY and updates value to ISO', async () => {
		let value = '';
		let errorMessage: string | null = null;
		render(DateInput, {
			get value() {
				return value;
			},
			set value(v) {
				value = v;
			},
			get errorMessage() {
				return errorMessage;
			},
			set errorMessage(v) {
				errorMessage = v;
			}
		});
		const input = page.getByRole('textbox');
		await input.fill('20122024');
		await expect.element(input).toHaveValue('20.12.2024');
		expect(value).toBe('2024-12-20');
		expect(errorMessage).toBeNull();
	});
});

// ─── Typing invalid month ─────────────────────────────────────────────────────

describe('DateInput – typing a date with invalid month', () => {
	it('sets errorMessage and clears value when month > 12', async () => {
		let value = '';
		let errorMessage: string | null = null;
		render(DateInput, {
			get value() {
				return value;
			},
			set value(v) {
				value = v;
			},
			get errorMessage() {
				return errorMessage;
			},
			set errorMessage(v) {
				errorMessage = v;
			}
		});
		const input = page.getByRole('textbox');
		await input.fill('22222222');
		await expect.element(input).toHaveValue('22.22.2222');
		expect(value).toBe('');
		expect(errorMessage).not.toBeNull();
	});
});

// ─── Typing partial date ──────────────────────────────────────────────────────

describe('DateInput – typing a partial date', () => {
	it('sets errorMessage and clears value when date is incomplete', async () => {
		let value = '';
		let errorMessage: string | null = null;
		render(DateInput, {
			get value() {
				return value;
			},
			set value(v) {
				value = v;
			},
			get errorMessage() {
				return errorMessage;
			},
			set errorMessage(v) {
				errorMessage = v;
			}
		});
		const input = page.getByRole('textbox');
		await input.fill('2212');
		await expect.element(input).toHaveValue('22.12');
		expect(value).toBe('');
		expect(errorMessage).not.toBeNull();
	});
});

// ─── Clearing date ────────────────────────────────────────────────────────────

describe('DateInput – clearing the date', () => {
	it('resets value and errorMessage to null when cleared', async () => {
		let value = '';
		let errorMessage: string | null = null;
		render(DateInput, {
			get value() {
				return value;
			},
			set value(v) {
				value = v;
			},
			get errorMessage() {
				return errorMessage;
			},
			set errorMessage(v) {
				errorMessage = v;
			}
		});
		const input = page.getByRole('textbox');
		// Type a valid date first
		await input.fill('20122024');
		expect(value).toBe('2024-12-20');
		// Now clear
		await input.fill('');
		expect(value).toBe('');
		expect(errorMessage).toBeNull();
	});

	it('fires onchange when the field is cleared', async () => {
		let called = 0;
		render(DateInput, { value: '2024-12-20', onchange: () => called++ });
		const input = page.getByRole('textbox');
		await input.fill('');
		expect(called).toBeGreaterThan(0);
	});
});

// ─── External value changes ───────────────────────────────────────────────────

describe('DateInput – external value changes', () => {
	it('clears display when value prop is reset to empty externally', async () => {
		const { rerender } = render(DateInput, { value: '1920-01-01' });
		const input = page.getByRole('textbox');
		await expect.element(input).toHaveValue('01.01.1920');
		await rerender({ value: '' });
		await expect.element(input).toHaveValue('');
	});

	it('updates display when value prop changes to a new date externally', async () => {
		const { rerender } = render(DateInput, { value: '1920-01-01' });
		const input = page.getByRole('textbox');
		await expect.element(input).toHaveValue('01.01.1920');
		await rerender({ value: '1945-05-08' });
		await expect.element(input).toHaveValue('08.05.1945');
	});
});

// ─── Hidden input ─────────────────────────────────────────────────────────────

describe('DateInput – hidden input for form submission', () => {
	it('renders a hidden input with the given name when name prop is set', async () => {
		render(DateInput, { name: 'documentDate' });
		const hidden = document.querySelector('input[type="hidden"][name="documentDate"]');
		expect(hidden).not.toBeNull();
	});

	it('does not render a hidden input when name prop is absent', async () => {
		render(DateInput, {});
		const hidden = document.querySelector('input[type="hidden"]');
		expect(hidden).toBeNull();
	});

	it('hidden input value reflects the ISO value', async () => {
		render(DateInput, { name: 'documentDate', value: '' });
		const input = page.getByRole('textbox');
		await input.fill('20122024');
		const hidden = document.querySelector<HTMLInputElement>(
			'input[type="hidden"][name="documentDate"]'
		);
		await expect.poll(() => hidden?.value).toBe('2024-12-20');
	});
});
