import { compile_to_volar_mappings } from '@tsrx/ripple';

function count_occurrences(string: string, sub_string: string): number {
	let count = 0;
	let pos = string.indexOf(sub_string);

	while (pos !== -1) {
		count++;
		pos = string.indexOf(sub_string, pos + sub_string.length);
	}

	return count;
}

// TryStatement in the Volar transform should behave like IfStatement and
// SwitchStatement: try blocks inside functions within a component must not
// be duplicated into the component body.

describe('compiler > Volar transform does not duplicate try blocks from functions', () => {
	it('try inside an async function', () => {
		const source = `export component App() {
	async function doWork() {
		try {
			await fetch('/api');
		} catch (e) {
			console.error(e);
		}
	}
	<div onclick={doWork}>{"click"}</div>
}`;
		const result = compile_to_volar_mappings(source, 'test.tsrx').code;

		expect(count_occurrences(result, 'try {')).toBe(1);
		expect(count_occurrences(result, 'catch')).toBe(1);
		expect(count_occurrences(result, 'await fetch')).toBe(1);
	});

	it('try inside an arrow function', () => {
		const source = `export component App() {
	const doWork = async () => {
		try {
			await fetch('/api');
		} catch (e) {}
	};
	<div onclick={doWork}>{"click"}</div>
}`;
		const result = compile_to_volar_mappings(source, 'test.tsrx').code;

		expect(count_occurrences(result, 'try {')).toBe(1);
		expect(count_occurrences(result, 'await fetch')).toBe(1);
	});

	it('try-catch-finally inside a function', () => {
		const source = `export component App() {
	async function save() {
		try {
			await fetch('/save');
		} catch (e) {
			console.error(e);
		} finally {
			console.log('done');
		}
	}
	<div onclick={save}>{"save"}</div>
}`;
		const result = compile_to_volar_mappings(source, 'test.tsrx').code;

		expect(count_occurrences(result, 'try {')).toBe(1);
		expect(count_occurrences(result, 'catch')).toBe(1);
		expect(count_occurrences(result, 'finally')).toBe(1);
	});

	it('try at component top level is preserved', () => {
		const source = `import { trackAsync } from 'ripple';
export component App() {
	try {
		let &[data] = trackAsync(() => fetch('/api'));
	} catch (e) {}
	<div>{"hi"}</div>
}`;
		const result = compile_to_volar_mappings(source, 'test.tsrx').code;

		expect(count_occurrences(result, 'try {')).toBe(1);
		expect(count_occurrences(result, 'trackAsync(() => fetch(\'/api\'))')).toBe(1);
	});

	it('component-level try and function-level try coexist without duplication', () => {
		const source = `import { trackAsync } from 'ripple';
export component App() {
	try {
		let &[data] = trackAsync(() => fetch('/init'));
	} catch (e) {}

	async function refresh() {
		try {
			await fetch('/refresh');
		} catch (e) {}
	}
	<div onclick={refresh}>{"click"}</div>
}`;
		const result = compile_to_volar_mappings(source, 'test.tsrx').code;

		expect(count_occurrences(result, 'try {')).toBe(2);
		expect(count_occurrences(result, 'trackAsync(() => fetch(\'/init\'))')).toBe(1);
		expect(count_occurrences(result, 'await fetch(\'/refresh\')')).toBe(1);
	});

	it('try in nested functions', () => {
		const source = `export component App() {
	function outer() {
		async function inner() {
			try {
				await fetch('/api');
			} catch (e) {}
		}
	}
	<div>{"hi"}</div>
}`;
		const result = compile_to_volar_mappings(source, 'test.tsrx').code;

		expect(count_occurrences(result, 'try {')).toBe(1);
		expect(count_occurrences(result, 'await fetch')).toBe(1);
	});

	it('multiple functions with try blocks each appear once', () => {
		const source = `export component App() {
	async function load() {
		try {
			await fetch('/load');
		} catch (e) {}
	}
	async function save() {
		try {
			await fetch('/save');
		} catch (e) {}
	}
	<div>{"hi"}</div>
}`;
		const result = compile_to_volar_mappings(source, 'test.tsrx').code;

		expect(count_occurrences(result, 'try {')).toBe(2);
		expect(count_occurrences(result, 'await fetch')).toBe(2);
	});

	it('try in object method', () => {
		const source = `export component App() {
	const handlers = {
		async onClick() {
			try {
				await fetch('/api');
			} catch (e) {}
		}
	};
	<div>{"hi"}</div>
}`;
		const result = compile_to_volar_mappings(source, 'test.tsrx').code;

		expect(count_occurrences(result, 'try {')).toBe(1);
		expect(count_occurrences(result, 'await fetch')).toBe(1);
	});
});
