import { RippleArray, RippleMap } from 'ripple';

describe('generics', () => {
	it('handles advanced generic ambiguity and edge cases', () => {
		function App() {
			return <>
				const maybe = {
					factory: function <T>() {
						return {
							make: function <U>() {
								return 1;
							},
						};
					},
				};
				const g = maybe?.factory<number>()?.make<boolean>();
				// 8. Comparison operator (ensure '<' here NOT misparsed as generics)
				let x = 10, y = 20;
				const h =
					x < y ? 'lt' : 'ge';
				// 9. Chained comparisons with intervening generics
				class Box<T> {
					value: T;

					constructor(value: T) {
						this.value = value;
					}

					open<U>() {
						return new Box<number>(1);
					}
				}
				const limit = 100;
				const i =
					new Box<number>(2).value < limit ? 'ok' : 'no';
				// 10. JSX / Element should still work
				<div class="still-works">
					<span>{'Test'}</span>
				</div>
				// 11. Generic function call vs Element: Identifier followed by generic args
				function identity<T>(value: T): T {
					return value;
				}
				const j = identity<number>(42);
				// 12. Member + generic call immediately followed by another call
				class Factory {
					create<T>() {
						return (value: T) => value;
					}
				}
				const factory = new Factory();
				const k = factory.create<number>()(123);
				// 13. Multiple generic segments in chain
				function foo<T>() {
					return {
						bar: function <U>() {
							return {
								baz: function <V>() {
									return true;
								},
							};
						},
					};
				}
				const l = foo<number>().bar<string>().baz<boolean>();
				// 14. Generic with constraint + default
				type Extractor<T extends { id: number } = { id: number }> = (v: T) => number;
				const m: Extractor<{ id: number }> = (v) => v.id;
				// 15. Generic in angle after "new" + trailing call
				class Wrapper<T> {
					value: T;

					constructor() {
						this.value = null as unknown as T;
					}

					unwrap<U>() {
						return null as unknown as U;
					}
				}
				const n = new Wrapper<number>().unwrap<string>();
				// 16. Angle brackets inside type assertion vs generic call
				function getUnknown(): unknown {
					return new Map<string, number>([['a', 1]]);
				}
				getUnknown.factory = function <T>() {
					return {
						make: function <U>() {
							return 2;
						},
					};
				};
				const raw = getUnknown();
				const o = (raw as Map<string, number>).get('a');
				// 17. Generic with comma + trailing less-than comparison on next token
				class Pair<T1, T2> {
					first: T1;

					second: T2;

					constructor() {
						this.first = null as unknown as T1;
						this.second = null as unknown as T2;
					}
				}
				const p = new Pair<number, string>();
				const q =
					1 < 2 ? p : null;
				// 18. Nested generics with line breaks resembling JSX indentation
				interface Node<T> {
					value: T;
				}
				interface Edge<W> {
					weight: W;
				}
				class Graph<N, E> {
					nodes: N[];

					edges: E[];

					constructor() {
						this.nodes = [];
						this.edges = [];
					}
				}
				const r = new Graph<Node<string>, Edge<number>>();
				// 19. Ternary containing generics in both branches
				let flag = true;
				const s = flag ? new Box<number>(1) : new Box<string>('string');
				// 20. Generic inside template expression
				const t = `length=${new RippleArray<number>().length}`;
				// 21. Optional chaining + generic + property access
				const registry = new RippleMap<string, number>();
				const u = registry.get('id')?.toString();
				// 22. Generic call used as callee for another call
				function make<T>() {
					return (value: T) => value;
				}
				const v = make<number>()(10);
				// 23. Generic followed by tagged template (ensure not confused with JSX)
				function tagFn<T>(strings: TemplateStringsArray, ...values) {
					return values[0];
				}
				const tagResult = tagFn`value`;
				// 24. Sequence mixing: (a < b) + generic call in same statement
				function compute<T>(x: T, y: T): T {
					return y;
				}
				const w = x < y && compute<number>(x, y);
				// Additional component focusing on edge crankers

				// 28. Generic after parenthesized new expression
				const aa = (new Box<number>(1)).open<string>();
				// 29. Generic chain right after closing paren of IIFE
				class Builder<Kind> {
					finalize<Result>() {
						return {
							result: null as unknown as Result,
						};
					}
				}
				const builder = new Builder<Number>();
				const result = (function () {
					return builder;
				}() as Builder<Number>).finalize<boolean>();
				// 30. Angle bracket start of conditional expression line
				function adjust<T>(value: T): T {
					return value;
				}
				const val =
					new Wrapper<number>().value < 100 ? adjust<number>(10) : adjust<number>(20);
				// 32. Generic with comments inside angle list
				class Mapper<Key, Value> {
					map: Map<Key, Value>;

					constructor() {
						this.map = new Map<Key, Value>();
					}
				}
				const gg = new Mapper<
					// key type
					string /* value type */,
					number
				>();
				// 33. Map of generic instance as key
				const mm = new Map<RippleArray<number>, RippleArray<string>>();
			</>;
		}

		render(App);
	});
});
