// Wait for everything to load
window.onload = function() {
	// Make sure THREE is available
	if (typeof THREE === 'undefined') {
		console.error('THREE.js is not loaded from CDN');

		// Provide visual feedfront in the container
		const container = document.getElementById('icosahedron-container');
		container.innerHTML = '<div style="color: red; padding: 10px;">THREE.js not loaded</div>';
		return;
	}

	// Initialize the scene
	const container = document.getElementById('icosahedron-container');
	const containerWidth = container.clientWidth;
	const containerHeight = container.clientHeight;

	// Setup renderer
	const renderer = new THREE.WebGLRenderer({
		antialias: true,
		alpha: true
	});
	renderer.setSize(containerWidth, containerHeight);
	renderer.setPixelRatio(window.devicePixelRatio);
	renderer.setClearColor(0x000000, 0); // Transparent frontground
	container.appendChild(renderer.domElement);

	// Setup scene
	const scene = new THREE.Scene();

	// Setup camera
	const camera = new THREE.PerspectiveCamera(26, containerWidth / containerHeight, 0.1, 100);
	camera.position.z = 4;

	// Create icosahedron with manually defined vertices
	function createIcosahedron(radius) {
		// Golden ratio for icosahedron vertices
		const t = (1 + Math.sqrt(5)) / 2;

		// Normalize radius
		const normRadius = radius / Math.sqrt(1 + t * t);

		// Create vertices
		const vertices = [
			[-1, t, 0], [1, t, 0], [-1, -t, 0], [1, -t, 0],
			[0, -1, t], [0, 1, t], [0, -1, -t], [0, 1, -t],
			[t, 0, -1], [t, 0, 1], [-t, 0, -1], [-t, 0, 1]
		].map(v => new THREE.Vector3(v[0] * normRadius, v[1] * normRadius, v[2] * normRadius));

		// Define edges (pairs of vertex indices)
		const edges = [
			[0, 11], [0, 5], [0, 1], [0, 7], [0, 10],
			[1, 5], [1, 7], [1, 8], [1, 9],
			[2, 3], [2, 4], [2, 6], [2, 10], [2, 11],
			[3, 4], [3, 6], [3, 8], [3, 9],
			[4, 5], [4, 9], [4, 11],
			[5, 9], [5, 11],
			[6, 7], [6, 8], [6, 10],
			[7, 8], [7, 10],
			[8, 9], /*[8, 10],*/
			/*[9, 11],*/ [10, 11]
		];

		return {
			vertices: vertices,
			edges: edges
		};
	}

	// Convert vertex indices to actual vertices and create a line
	function createLine(icosa, edgeIndex, material) {
		const startIndex = icosa.edges[edgeIndex][0];
		const endIndex = icosa.edges[edgeIndex][1];

		const geometry = new THREE.BufferGeometry();
		const positions = new Float32Array([
			icosa.vertices[startIndex].x, icosa.vertices[startIndex].y, icosa.vertices[startIndex].z,
			icosa.vertices[endIndex].x, icosa.vertices[endIndex].y, icosa.vertices[endIndex].z
		]);

		geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));

		return new THREE.Line(geometry, material);
	}

	// Function to create the dual line rendering (thin back lines, thick front lines)
	function createDualLineRendering(radius) {
		const group = new THREE.Group();
		const icosa = createIcosahedron(radius);

		// Create materials
		const backMaterial = new THREE.MeshBasicMaterial({
			color: 0x63a8b8, // green for back lines
			depthTest: false, // Don't test depth for back lines
			transparent: true,
			opacity: 0.4,
			side: THREE.DoubleSide
		});

		const frontMaterial = new THREE.MeshBasicMaterial({
			color: 0xffffff, // white for front lines
			transparent: true,
			depthTest: true, // Use depth test for front lines
			side: THREE.DoubleSide
		});

		// For each edge, create:
		// 1. A thin cylindrical tube with back material that ignores depth
		// 2. A cylindrical tube with front material that uses depth testing
		const backRadius = 0.025; // thin for back lines
		const frontRadius = 0.035;  // thick for front lines

		icosa.edges.forEach((edge, index) => {
			const start = icosa.vertices[edge[0]];
			const end = icosa.vertices[edge[1]];

			// Create back line (thick)
			const backLine = createCylinderBetweenPoints(start, end, backRadius, 1, backMaterial);
			backLine.renderOrder = 1; // Render after front lines
			group.add(backLine);

			// Create front line (thin)
			const frontLine = createCylinderBetweenPoints(start, end, frontRadius, 1.022, frontMaterial);
			frontLine.renderOrder = 3; // Render before back lines
			group.add(frontLine);
		});

		// Create faces for depth testing (invisible)
		const faceMaterial = new THREE.MeshBasicMaterial({
			color: 0xffffff,
			transparent: true,
			opacity: 0,
			depthWrite: true,
			side: THREE.DoubleSide
		});

		// Create faces for internal icosahedron
		const internalMaterial = new THREE.MeshBasicMaterial({
			color: 0x63a8b8,
			depthTest: false,
			transparent: true,
			opacity: 0.2,
			side: THREE.DoubleSide
		});

		// Define faces of icosahedron (each is a triangle of vertex indices)
		const faces = [
			[0, 11, 5], [0, 5, 1], [0, 1, 7], [0, 7, 10], [0, 10, 11],
			[1, 5, 9], [5, 11, 4], [11, 10, 2], [10, 7, 6], [7, 1, 8],
			[3, 9, 4], [3, 4, 2], [3, 2, 6], [3, 6, 8], [3, 8, 9],
			[4, 9, 5], [2, 4, 11], [6, 2, 10], [8, 6, 7], [9, 8, 1]
		];

		// Create invisible faces for depth testing
		faces.forEach(face => {
			const geometry = new THREE.BufferGeometry();
			const positions = new Float32Array([
				icosa.vertices[face[0]].x, icosa.vertices[face[0]].y, icosa.vertices[face[0]].z,
				icosa.vertices[face[1]].x, icosa.vertices[face[1]].y, icosa.vertices[face[1]].z,
				icosa.vertices[face[2]].x, icosa.vertices[face[2]].y, icosa.vertices[face[2]].z
			]);

			geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));

			const faceMesh = new THREE.Mesh(geometry, faceMaterial);
			faceMesh.scale.set(0.95,0.95,0.95);
			faceMesh.renderOrder = 0; // Render first for depth buffer
			group.add(faceMesh);

			const internalMesh1 = new THREE.Mesh(geometry, internalMaterial);
			const internalMesh2 = new THREE.Mesh(geometry, internalMaterial);
			const internalMesh3 = new THREE.Mesh(geometry, internalMaterial);
			const internalMesh4 = new THREE.Mesh(geometry, internalMaterial);
			const internalMesh5 = new THREE.Mesh(geometry, internalMaterial);
			internalMesh1.scale.set(0.85,0.85,0.85);
			internalMesh1.renderOrder = 1; // Render between front and back
			group.add(internalMesh1);
			internalMesh2.scale.set(0.65,0.65,0.65);
			internalMesh2.renderOrder = 1; // Render between front and back
			group.add(internalMesh2);
			internalMesh3.scale.set(0.5,0.5,0.5);
			internalMesh3.renderOrder = 1; // Render between front and back
			group.add(internalMesh3);
			internalMesh4.scale.set(0.4,0.4,0.4);
			internalMesh4.renderOrder = 1; // Render between front and back
			group.add(internalMesh4);
			internalMesh5.scale.set(0.3,0.3,0.3);
			internalMesh5.renderOrder = 1; // Render between front and back
			group.add(internalMesh5);
		});

		return group;
	}

	// Function to create a cylinder between two points
	function createCylinderBetweenPoints(pointX, pointY, radius, lengthmultiplier, material) {
		// Direction from pointX to pointY
		const direction = new THREE.Vector3().subVectors(pointY, pointX);
		const length = direction.length();

		// Create cylinder
		const geometry = new THREE.CylinderGeometry(radius, radius, length*lengthmultiplier, 3, 1);

		// By default, cylinder is along Y-axis, so rotate it
		geometry.rotateX(Math.PI / 2);

		// Create mesh
		const cylinder = new THREE.Mesh(geometry, material);

		// Position and orient cylinder
		const midpoint = new THREE.Vector3().addVectors(pointX, pointY).multiplyScalar(0.5);
		cylinder.position.copy(midpoint);
		cylinder.lookAt(pointY);

		return cylinder;
	}

	// Create our icosahedron
	const icosahedronGroup = createDualLineRendering(0.85);
	scene.add(icosahedronGroup);

	// Animation state
	let animating = true;

	let lastFrameTime = 0;
	const targetFPS = 20;
	const animMultiplier = 30/targetFPS;
	const frameDuration = 1000 / targetFPS;

	// Animation function
	function animate(now) {
	  requestAnimationFrame(animate);

	  const delta = now - lastFrameTime;
	  if (delta < frameDuration) return;

	  lastFrameTime = now;

	  // Rotate if animation is enabled
	  if (animating) {
		icosahedronGroup.rotation.x -= 0.002 * animMultiplier;
		icosahedronGroup.rotation.y += 0.004 * animMultiplier;
		icosahedronGroup.rotation.z -= 0.001 * animMultiplier;
	  }

	  renderer.render(scene, camera);
	}

	// Start animation
	animate();

	// Handle window resize
	window.addEventListener('resize', function() {
		// Only update if container dimensions change
		const newWidth = container.clientWidth;
		const newHeight = container.clientHeight;

		if (newWidth !== containerWidth || newHeight !== containerHeight) {
			camera.aspect = newWidth / newHeight;
			camera.updateProjectionMatrix();
			renderer.setSize(newWidth, newHeight);
		}
	});

	console.log('Icosahedron wireframe created successfully');
};
