<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>Fruit Fall 3D</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <style>
        body { margin: 0; overflow: hidden; font-family: Arial, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f0f0f0; }
        #gameCanvas { display: block; }
        #ui-container {
            position: absolute;
            top: 10px;
            left: 10px;
            padding: 10px;
            background-color: rgba(0,0,0,0.5);
            color: white;
            border-radius: 5px;
            z-index: 100;
        }
        #score { font-size: 1.5em; margin-bottom: 5px; }
        #start-button, #reset-button {
            padding: 8px 15px;
            font-size: 1em;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 3px;
            cursor: pointer;
            margin-top: 5px;
        }
        #reset-button { background-color: #f44336; display: none;}
        #game-over-message {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: white;
            background-color: rgba(0,0,0,0.7);
            padding: 20px;
            border-radius: 10px;
            font-size: 2em;
            text-align: center;
            z-index: 101;
            display: none; /* Hidden by default */
        }
    </style>
</head>
<body>
    <div id="ui-container">
        <div id="score">Score: 0</div>
        <button id="start-button">Start Game</button>
        <button id="reset-button">Play Again</button>
    </div>
    <div id="game-over-message">
        Game Over!<br>
        <span id="final-score-message"></span>
    </div>
    <canvas id="gameCanvas"></canvas>

    <script>
        let scene, camera, renderer;
        let fruits = [];
        let score = 0;
        let gameActive = false;
        let raycaster, mouse; // For click detection
        let audioContext;
        let gameTimer, timeLeft;
        const GAME_DURATION = 30; // seconds

        const scoreElement = document.getElementById('score');
        const startButton = document.getElementById('start-button');
        const resetButton = document.getElementById('reset-button');
        const gameOverMessageDiv = document.getElementById('game-over-message');
        const finalScoreMessageSpan = document.getElementById('final-score-message');


        const fruitTypes = [
            { name: 'Mango', color: 0xFFBF00, size: 0.5, points: 10 },
            { name: 'Apple', color: 0xFF0000, size: 0.4, points: 10 },
            { name: 'Banana', color: 0xFFFF00, size: 0.35, points: 15 }, // Represented as sphere
            { name: 'Grapes', color: 0x800080, size: 0.3, points: 20 },
            { name: 'Watermelon', color: 0x00FF00, size: 0.7, points: 5 }
        ];

        function initAudio() {
            if (!audioContext) {
                audioContext = new (window.AudioContext || window.webkitAudioContext)();
            }
        }

        function playSound(type = 'click', freq = 440, duration = 0.05) {
            if (!audioContext) return;
            const oscillator = audioContext.createOscillator();
            const gainNode = audioContext.createGain();
            oscillator.connect(gainNode);
            gainNode.connect(audioContext.destination);

            oscillator.type = (type === 'miss') ? 'sawtooth' : 'triangle';
            oscillator.frequency.setValueAtTime(freq, audioContext.currentTime);
            gainNode.gain.setValueAtTime(0.15, audioContext.currentTime); // Lowered volume
            gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + duration);
            
            oscillator.start();
            oscillator.stop(audioContext.currentTime + duration);
        }

        function init() {
            // Scene
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0x87CEEB); // Sky blue

            // Camera
            camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
            camera.position.set(0, 2, 7); // Positioned to see the falling fruits well
            camera.lookAt(0, 0, 0);

            // Renderer
            renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('gameCanvas'), antialias: true });
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.shadowMap.enabled = true;

            // Lighting
            const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
            scene.add(ambientLight);
            const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
            directionalLight.position.set(5, 10, 7);
            directionalLight.castShadow = true;
            scene.add(directionalLight);

            // Ground (optional, for visual reference)
            const groundGeometry = new THREE.PlaneGeometry(20, 20);
            const groundMaterial = new THREE.MeshStandardMaterial({ color: 0x228B22, side: THREE.DoubleSide }); // Forest green
            const ground = new THREE.Mesh(groundGeometry, groundMaterial);
            ground.rotation.x = -Math.PI / 2;
            ground.position.y = -5; // Fruits fall past this
            ground.receiveShadow = true;
            scene.add(ground);

            // Raycaster for mouse clicks
            raycaster = new THREE.Raycaster();
            mouse = new THREE.Vector2();

            // Event Listeners
            window.addEventListener('resize', onWindowResize, false);
            renderer.domElement.addEventListener('click', onClick, false); // For desktop
            renderer.domElement.addEventListener('touchstart', onTouch, false); // For mobile

            startButton.addEventListener('click', startGame);
            resetButton.addEventListener('click', startGame); // Reset button also starts the game
        }

        function startGame() {
            initAudio();
            score = 0;
            timeLeft = GAME_DURATION;
            updateScoreDisplay();
            gameActive = true;
            fruits.forEach(fruit => scene.remove(fruit.mesh)); // Clear existing fruits
            fruits = [];
            
            startButton.style.display = 'none';
            resetButton.style.display = 'none';
            gameOverMessageDiv.style.display = 'none';

            if (gameTimer) clearInterval(gameTimer);
            gameTimer = setInterval(() => {
                timeLeft--;
                // Optionally display timer: scoreElement.textContent = `Score: ${score} | Time: ${timeLeft}`;
                if (timeLeft <= 0) {
                    endGame();
                }
            }, 1000);

            spawnFruitLoop(); // Start spawning fruits
            if (!renderer.xr.isPresenting) animate(); // Ensure animate isn't called twice if in XR
        }
        
        function endGame() {
            gameActive = false;
            clearInterval(gameTimer);
            clearTimeout(fruitSpawnTimeout); // Stop spawning new fruits

            finalScoreMessageSpan.textContent = `Your Score: ${score}`;
            gameOverMessageDiv.style.display = 'flex';
            resetButton.style.display = 'inline-block';
        }


        let fruitSpawnTimeout;
        function spawnFruitLoop() {
            if (!gameActive) return;
            createFruit();
            const spawnInterval = Math.random() * 1500 + 500; // 0.5 to 2 seconds
            fruitSpawnTimeout = setTimeout(spawnFruitLoop, spawnInterval);
        }

        function createFruit() {
            if (!gameActive) return;

            const type = fruitTypes[Math.floor(Math.random() * fruitTypes.length)];
            const geometry = new THREE.SphereGeometry(type.size, 16, 12);
            const material = new THREE.MeshStandardMaterial({ color: type.color, roughness: 0.5, metalness: 0.1 });
            const fruitMesh = new THREE.Mesh(geometry, material);
            fruitMesh.castShadow = true;

            // Random spawn position at the top
            fruitMesh.position.x = (Math.random() - 0.5) * 10; // Range: -5 to 5
            fruitMesh.position.y = 7 + Math.random() * 3;      // Start above camera view
            fruitMesh.position.z = (Math.random() - 0.5) * 4;  // Some depth variation

            fruitMesh.userData = { type: type.name, points: type.points, fallSpeed: 0.02 + Math.random() * 0.03 };
            
            scene.add(fruitMesh);
            fruits.push({ mesh: fruitMesh, data: fruitMesh.userData });
        }

        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }
        
        function handleInteraction(clientX, clientY) {
            if (!gameActive) return;

            mouse.x = (clientX / window.innerWidth) * 2 - 1;
            mouse.y = -(clientY / window.innerHeight) * 2 + 1;
            raycaster.setFromCamera(mouse, camera);

            const fruitMeshes = fruits.map(f => f.mesh);
            const intersects = raycaster.intersectObjects(fruitMeshes);

            if (intersects.length > 0) {
                const clickedFruitMesh = intersects[0].object;
                const fruitIndex = fruits.findIndex(f => f.mesh === clickedFruitMesh);

                if (fruitIndex !== -1) {
                    const fruitData = fruits[fruitIndex].data;
                    score += fruitData.points;
                    updateScoreDisplay();
                    playSound('click', 300 + Math.random()*200);

                    // Simple "pop" effect: shrink and remove
                    // More complex particle effects are possible but add overhead
                    clickedFruitMesh.scale.set(0.1,0.1,0.1); // Visually shrink
                    setTimeout(() => { // Remove after slight delay
                        scene.remove(clickedFruitMesh);
                    }, 50);
                    fruits.splice(fruitIndex, 1);
                }
            }
        }

        function onClick(event) {
            handleInteraction(event.clientX, event.clientY);
        }
        
        function onTouch(event) {
            if (event.touches.length > 0) {
                handleInteraction(event.touches[0].clientX, event.touches[0].clientY);
            }
        }

        function updateScoreDisplay() {
            scoreElement.textContent = `Score: ${score} | Time: ${timeLeft}`;
        }

        function animate() {
            if (!gameActive && timeLeft <= 0) { // If game ended, stop animation loop
                 return;
            }
            requestAnimationFrame(animate);

            if (gameActive) {
                // Fruit falling logic
                for (let i = fruits.length - 1; i >= 0; i--) {
                    const fruitObj = fruits[i];
                    fruitObj.mesh.position.y -= fruitObj.data.fallSpeed;
                    fruitObj.mesh.rotation.x += 0.01;
                    fruitObj.mesh.rotation.y += 0.01;

                    // Remove fruit if it falls below a certain point (miss)
                    if (fruitObj.mesh.position.y < -6) { // Below the ground plane
                        scene.remove(fruitObj.mesh);
                        fruits.splice(i, 1);
                        // playSound('miss', 150); // Optional miss sound
                        // score -= 5; // Optional penalty
                        updateScoreDisplay();
                    }
                }
            }
            renderer.render(scene, camera);
        }

        // --- Start ---
        init();
        // startGame(); // Initial call to animate if not waiting for button
    </script>
</body>
</html>