import { track, trackSplit, effect, flushSync, type Props } from 'ripple';

describe('composite > props', () => {
	it('correctly handles default prop values', () => {
		component Child({ foo = 456 }) {
			<div>{foo}</div>
		}

		component App() {
			let foo = track(123);

			<Child />
			<Child {@foo} />
		}

		render(App);

		expect(container.querySelectorAll('div')[0].textContent).toBe('456');
		expect(container.querySelectorAll('div')[1].textContent).toBe('123');
	});

	it('correctly handles default prop values #2', () => {
		component Child({ foo = 456 }) {
			<div>{foo}</div>
		}

		component App() {
			let foo = 123;

			<Child />
			<Child {foo} />
		}

		render(App);

		expect(container.querySelectorAll('div')[0].textContent).toBe('456');
		expect(container.querySelectorAll('div')[1].textContent).toBe('123');
	});

	it('correctly handles no props', () => {
		component Child(props: { foo?: Tracked<number> }) {
			<div>{props.@foo}</div>
		}

		component App() {
			let foo = track(123);

			<Child />
			<Child {foo} />
		}

		render(App);

		expect(container.querySelectorAll('div')[0].textContent).toBe('');
		expect(container.querySelectorAll('div')[1].textContent).toBe('123');
	});

	it('correctly handles no props #2', () => {
		component Child({ foo }) {
			<div>{foo}</div>
		}

		component App() {
			let foo = track(123);

			<Child />
			<Child {@foo} />
		}

		render(App);

		expect(container.querySelectorAll('div')[0].textContent).toBe('');
		expect(container.querySelectorAll('div')[1].textContent).toBe('123');
	});

	it('mutating a tracked value prop should work as intended', () => {
		const logs: number[] = [];

		component Counter({ count }) {
			effect(() => {
				logs.push(@count);
			});

			<button onClick={() => @count = @count + 1}>{'+'}</button>
		}

		component App() {
			const count = track(0);

			<div>
				<Counter {count} />
			</div>
		}

		render(App);
		flushSync();

		expect(logs).toEqual([0]);

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

		expect(logs).toEqual([0, 1]);
	});

	it('correctly retains prop accessors and reactivity when using rest props', () => {
		component Button(props: Props) {
			const [children, rest] = trackSplit(props, ['children']);
			<button {...@rest}>
				<@children />
			</button>
			<style>
				.on {
					color: blue;
				}
				.off {
					color: red;
				}
			</style>
		}

		component Toggle(props) {
			const [pressed, rest] = trackSplit(props, ['pressed']);
			const onClick = () => @pressed = !@pressed;
			<Button {...@rest} class={@pressed ? 'on' : 'off'} {onClick}>{'button 1'}</Button>
			<Button class={@pressed ? 'on' : 'off'} {onClick}>{'button 2'}</Button>
		}

		component App() {
			const pressed = track(true);
			<Toggle {pressed} />
		}

		render(App);
		const button1 = container.querySelectorAll('button')[0];

		const button2 = container.querySelectorAll('button')[1];

		expect(button1.className).toContain('on');
		expect(button2.className).toContain('on');

		button1.click();
		flushSync();

		expect(button1.className).toContain('off');
		expect(button2.className).toContain('off');
	});
});
