import { RippleURL, flushSync } from 'ripple';

describe('RippleURL > reactivity', () => {
	it('handles protocol changes with reactivity', () => {
		function URLTest() @{
			const url = RippleURL('https://example.com/path');
			<>
				<button onClick={() => (url.protocol = 'http:')}>{'Change Protocol'}</button>
				<pre>{url.href}</pre>
				<pre>{url.protocol}</pre>
				<pre>{url.origin}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/path');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('https:');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('https://example.com');

		// Change protocol
		button.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe('http://example.com/path');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('http:');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('http://example.com');
	});

	it('handles hostname changes with reactivity', () => {
		function URLTest() @{
			const url = RippleURL('https://example.com/path');
			<>
				<button onClick={() => (url.hostname = 'newdomain.com')}>{'Change Hostname'}</button>
				<pre>{url.href}</pre>
				<pre>{url.hostname}</pre>
				<pre>{url.host}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/path');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('example.com');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('example.com');

		// Change hostname
		button.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe('https://newdomain.com/path');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('newdomain.com');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('newdomain.com');
	});

	it('handles port changes with reactivity', () => {
		function URLTest() @{
			const url = RippleURL('https://example.com:8080/path');
			<>
				<button onClick={() => (url.port = '9090')}>{'Change Port'}</button>
				<pre>{url.href}</pre>
				<pre>{url.port}</pre>
				<pre>{url.host}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com:8080/path');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('8080');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('example.com:8080');

		// Change port
		button.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com:9090/path');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('9090');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('example.com:9090');
	});

	it('handles host changes with reactivity', () => {
		function URLTest() @{
			const url = RippleURL('https://example.com:8080/path');
			<>
				<button onClick={() => (url.host = 'newdomain.com:9090')}>{'Change Host'}</button>
				<pre>{url.href}</pre>
				<pre>{url.host}</pre>
				<pre>{url.hostname}</pre>
				<pre>{url.port}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com:8080/path');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('example.com:8080');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('example.com');
		expect(container.querySelectorAll('pre')[3].textContent).toBe('8080');

		// Change host
		button.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://newdomain.com:9090/path',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('newdomain.com:9090');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('newdomain.com');
		expect(container.querySelectorAll('pre')[3].textContent).toBe('9090');
	});

	it('handles pathname changes with reactivity', () => {
		function URLTest() @{
			const url = RippleURL('https://example.com/old-path');
			<>
				<button onClick={() => (url.pathname = '/new-path')}>{'Change Pathname'}</button>
				<pre>{url.href}</pre>
				<pre>{url.pathname}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/old-path');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('/old-path');

		// Change pathname
		button.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe('https://example.com/new-path');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('/new-path');
	});

	it('handles search changes with reactivity', () => {
		function URLTest() @{
			const url = RippleURL('https://example.com/path?foo=bar');
			<>
				<button onClick={() => (url.search = '?baz=qux')}>{'Change Search'}</button>
				<pre>{url.href}</pre>
				<pre>{url.search}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://example.com/path?foo=bar',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('?foo=bar');

		// Change search
		button.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://example.com/path?baz=qux',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('?baz=qux');
	});

	it('handles hash changes with reactivity', () => {
		function URLTest() @{
			const url = RippleURL('https://example.com/path#section1');
			<>
				<button onClick={() => (url.hash = '#section2')}>{'Change Hash'}</button>
				<pre>{url.href}</pre>
				<pre>{url.hash}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://example.com/path#section1',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('#section1');

		// Change hash
		button.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://example.com/path#section2',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('#section2');
	});

	it('handles username changes with reactivity', () => {
		function URLTest() @{
			const url = RippleURL('https://user:pass@example.com/path');
			<>
				<button onClick={() => (url.username = 'newuser')}>{'Change Username'}</button>
				<pre>{url.href}</pre>
				<pre>{url.username}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://user:pass@example.com/path',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('user');

		// Change username
		button.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://newuser:pass@example.com/path',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('newuser');
	});

	it('handles password changes with reactivity', () => {
		function URLTest() @{
			const url = RippleURL('https://user:pass@example.com/path');
			<>
				<button onClick={() => (url.password = 'newpass')}>{'Change Password'}</button>
				<pre>{url.href}</pre>
				<pre>{url.password}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://user:pass@example.com/path',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('pass');

		// Change password
		button.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://user:newpass@example.com/path',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('newpass');
	});

	it('handles href changes with reactivity', () => {
		function URLTest() @{
			const url = RippleURL('https://example.com/path?foo=bar#section');
			<>
				<button
					onClick={() => (url.href = 'https://newdomain.com:9090/newpath?baz=qux#newsection')}
				>{'Change Href'}</button>
				<pre>{url.href}</pre>
				<pre>{url.protocol}</pre>
				<pre>{url.hostname}</pre>
				<pre>{url.port}</pre>
				<pre>{url.pathname}</pre>
				<pre>{url.search}</pre>
				<pre>{url.hash}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://example.com/path?foo=bar#section',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('https:');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('example.com');
		expect(container.querySelectorAll('pre')[3].textContent).toBe('');
		expect(container.querySelectorAll('pre')[4].textContent).toBe('/path');
		expect(container.querySelectorAll('pre')[5].textContent).toBe('?foo=bar');
		expect(container.querySelectorAll('pre')[6].textContent).toBe('#section');

		// Change href
		button.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://newdomain.com:9090/newpath?baz=qux#newsection',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('https:');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('newdomain.com');
		expect(container.querySelectorAll('pre')[3].textContent).toBe('9090');
		expect(container.querySelectorAll('pre')[4].textContent).toBe('/newpath');
		expect(container.querySelectorAll('pre')[5].textContent).toBe('?baz=qux');
		expect(container.querySelectorAll('pre')[6].textContent).toBe('#newsection');
	});

	it('handles origin property reactivity', () => {
		function URLTest() @{
			const url = RippleURL('https://example.com:8080/path');
			<>
				<button onClick={() => (url.protocol = 'http:')}>{'Change Protocol'}</button>
				<button onClick={() => (url.hostname = 'newdomain.com')}>{'Change Hostname'}</button>
				<button onClick={() => (url.port = '9090')}>{'Change Port'}</button>
				<pre>{url.origin}</pre>
			</>
		}

		render(URLTest);

		const buttons = container.querySelectorAll('button');

		// Initial state
		expect(container.querySelector('pre').textContent).toBe('https://example.com:8080');

		// Change protocol
		buttons[0].click();
		flushSync();
		expect(container.querySelector('pre').textContent).toBe('http://example.com:8080');

		// Change hostname
		buttons[1].click();
		flushSync();
		expect(container.querySelector('pre').textContent).toBe('http://newdomain.com:8080');

		// Change port
		buttons[2].click();
		flushSync();
		expect(container.querySelector('pre').textContent).toBe('http://newdomain.com:9090');
	});
	it('handles searchParams changes with reactivity', () => {
		function URLTest() @{
			const url = RippleURL('https://example.com/path?foo=bar');
			const params = url.searchParams;
			<>
				<button onClick={() => params.set('foo', 'updated')}>{'Update Foo'}</button>
				<button onClick={() => params.append('baz', 'qux')}>{'Add Baz'}</button>
				<pre>{url.href}</pre>
				<pre>{url.search}</pre>
				<pre>{params.get('foo')}</pre>
			</>
		}

		render(URLTest);

		const updateButton = container.querySelectorAll('button')[0];
		const addButton = container.querySelectorAll('button')[1];

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://example.com/path?foo=bar',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('?foo=bar');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('bar');

		// Update param
		updateButton.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://example.com/path?foo=updated',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('?foo=updated');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('updated');

		// Add param
		addButton.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe(
			'https://example.com/path?foo=updated&baz=qux',
		);
		expect(container.querySelectorAll('pre')[1].textContent).toBe('?foo=updated&baz=qux');
	});

	it('handles search property updates reflected in searchParams', () => {
		function URLTest() @{
			const url = RippleURL('https://example.com/path?foo=bar');
			const params = url.searchParams;
			<>
				<button onClick={() => (url.search = '?baz=qux&test=value')}>{'Change Search'}</button>
				<pre>{url.search}</pre>
				<pre>{params.get('foo')}</pre>
				<pre>{params.get('baz')}</pre>
				<pre>{params.get('test')}</pre>
				<pre>{params.size}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe('?foo=bar');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('bar');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('');
		expect(container.querySelectorAll('pre')[3].textContent).toBe('');
		expect(container.querySelectorAll('pre')[4].textContent).toBe('1');

		// Change search
		button.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe('?baz=qux&test=value');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('qux');
		expect(container.querySelectorAll('pre')[3].textContent).toBe('value');
		expect(container.querySelectorAll('pre')[4].textContent).toBe('2');
	});

	it('handles multiple URL property changes in sequence', () => {
		function URLTest() @{
			const url = RippleURL('https://example.com/path');
			<>
				<button
					onClick={() => {
						url.protocol = 'http:';
						url.hostname = 'newdomain.com';
						url.port = '8080';
						url.pathname = '/api';
						url.search = '?key=value';
						url.hash = '#section';
					}}
				>{'Change All'}</button>
				<pre>{url.href}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelector('pre').textContent).toBe('https://example.com/path');

		// Change all properties
		button.click();
		flushSync();

		expect(container.querySelector('pre').textContent).toBe(
			'http://newdomain.com:8080/api?key=value#section',
		);
	});

	it('handles href change updates all properties and searchParams', () => {
		function URLTest() @{
			const url = RippleURL('https://old.com/old?foo=bar#old');
			const params = url.searchParams;
			<>
				<button
					onClick={() => (url.href = 'https://new.com:9090/new?baz=qux#new')}
				>{'Change Href'}</button>
				<pre>{params.get('foo')}</pre>
				<pre>{params.get('baz')}</pre>
				<pre>{params.size}</pre>
				<pre>{url.pathname}</pre>
			</>
		}

		render(URLTest);

		const button = container.querySelector('button');

		// Initial state
		expect(container.querySelectorAll('pre')[0].textContent).toBe('bar');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('1');
		expect(container.querySelectorAll('pre')[3].textContent).toBe('/old');

		// Change href
		button.click();
		flushSync();

		expect(container.querySelectorAll('pre')[0].textContent).toBe('');
		expect(container.querySelectorAll('pre')[1].textContent).toBe('qux');
		expect(container.querySelectorAll('pre')[2].textContent).toBe('1');
		expect(container.querySelectorAll('pre')[3].textContent).toBe('/new');
	});
});
