import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/svelte';
import SearchInput from '$lib/components/molecules/SearchInput/SearchInput.svelte';

describe('SearchInput', () => {
	beforeEach(() => {
		vi.useFakeTimers();
	});

	afterEach(() => {
		vi.useRealTimers();
	});

	it('renders input with default placeholder', () => {
		render(SearchInput, {
			props: { onSearch: vi.fn() }
		});

		expect(screen.getByPlaceholderText('Rechercher...')).toBeTruthy();
	});

	it('renders input with custom placeholder', () => {
		render(SearchInput, {
			props: { onSearch: vi.fn(), placeholder: 'Chercher un utilisateur...' }
		});

		expect(screen.getByPlaceholderText('Chercher un utilisateur...')).toBeTruthy();
	});

	it('debounces input and calls onSearch after delay', async () => {
		const onSearch = vi.fn();
		render(SearchInput, {
			props: { onSearch, debounceMs: 300 }
		});

		const input = screen.getByRole('searchbox');
		await fireEvent.input(input, { target: { value: 'test' } });

		// Should not be called immediately
		expect(onSearch).not.toHaveBeenCalled();

		// Advance past the debounce time
		vi.advanceTimersByTime(300);

		expect(onSearch).toHaveBeenCalledOnce();
		expect(onSearch).toHaveBeenCalledWith('test');
	});

	it('cancels pending debounce on new input', async () => {
		const onSearch = vi.fn();
		render(SearchInput, {
			props: { onSearch, debounceMs: 300 }
		});

		const input = screen.getByRole('searchbox');

		// Type first value
		await fireEvent.input(input, { target: { value: 'te' } });
		vi.advanceTimersByTime(200);

		// Type second value before debounce fires
		await fireEvent.input(input, { target: { value: 'test' } });
		vi.advanceTimersByTime(300);

		// Should only be called once with the final value
		expect(onSearch).toHaveBeenCalledOnce();
		expect(onSearch).toHaveBeenCalledWith('test');
	});

	it('clears input on Escape key', async () => {
		const onSearch = vi.fn();
		render(SearchInput, {
			props: { value: 'initial', onSearch }
		});

		const input = screen.getByRole('searchbox');
		await fireEvent.keyDown(input, { key: 'Escape' });

		expect(onSearch).toHaveBeenCalledWith('');
	});

	it('calls onSearch immediately on clear button click', async () => {
		const onSearch = vi.fn();
		render(SearchInput, {
			props: { value: 'something', onSearch }
		});

		const clearButton = screen.getByRole('button', { name: 'Effacer la recherche' });
		await fireEvent.click(clearButton);

		// Should be called immediately (no debounce)
		expect(onSearch).toHaveBeenCalledWith('');
	});

	it('shows clear button only when input has value', () => {
		const { container } = render(SearchInput, {
			props: { onSearch: vi.fn() }
		});

		// No clear button initially (empty value)
		expect(container.querySelector('.search-clear')).toBeNull();
	});

	it('shows clear button when initial value is provided', () => {
		const { container } = render(SearchInput, {
			props: { value: 'test', onSearch: vi.fn() }
		});

		expect(container.querySelector('.search-clear')).not.toBeNull();
	});
});
