/**
 * Improved Golf Ball Camera System
 * Provides smooth camera tracking for golf balls using Minecraft's camera API
 */

import { world, system } from '@minecraft/server';
import { getPlayerCameraTrackingPreference } from './score.js';

export class GolfCameraSystem {
    constructor() {
        this.activeTrackers = new Map(); // playerId -> tracking data
        this.updateInterval = null;
        this.initialize();
    }

    initialize() {
        // Start the camera update loop
        this.startUpdateLoop();
    }

    startUpdateLoop() {
        if (this.updateInterval) {
            system.clearRun(this.updateInterval);
        }
        
        this.updateInterval = system.runInterval(() => {
            this.updateCameraTracking();
        }, 2); // Update every 2 ticks for smooth but not excessive updates
    }

    startBallTracking(player, golfBall) {
        if (!player || !golfBall) {
            // console.warn("Camera: Cannot start tracking - invalid player or ball");
            return;
        }

        const playerId = player.id;
        
        // Check if player has camera tracking enabled
        if (!getPlayerCameraTrackingPreference(playerId)) {
            // Player has disabled camera tracking, don't start tracking
            return;
        }
        
        // Stop any existing tracking for this player
        this.stopTracking(playerId);

        // Validate ball exists
        try {
            if (!golfBall) {
                // console.warn("Camera: Cannot track - ball is invalid");
                return;
            }
        } catch (e) {
            // console.warn("Camera: Error validating ball", e);
            return;
        }

        // Start tracking
        this.activeTrackers.set(playerId, {
            player: player,
            ball: golfBall,
            ballLanded: false,
            landTime: 0,
            trackingStartTime: system.currentTick,
            lastVelocityCheck: 0,
            stationaryTicks: 0
        });

        // console.log(`Camera: Started tracking ball for player ${player.name}`);
        // player.sendMessage("§aCamera following golf ball...");
    }

    updateCameraTracking() {
        if (this.activeTrackers.size === 0) {
            return;
        }

        const currentTick = system.currentTick;
        const trackersToRemove = [];

        for (const [playerId, tracker] of this.activeTrackers) {
            const { player, ball } = tracker;
            
            // Validate player exists
            if (!player) {
                // console.warn(`Camera: Player invalid for ID ${playerId}`);
                trackersToRemove.push(playerId);
                continue;
            }
            
            // Validate ball exists
            try {
                if (!ball) {
                    // console.warn(`Camera: Ball invalid for player ${player.name}`);
                    this.returnToPlayer(playerId);
                    trackersToRemove.push(playerId);
                    continue;
                }
            } catch (e) {
                // console.warn(`Camera: Error validating ball for player ${player.name}`, e);
                this.returnToPlayer(playerId);
                trackersToRemove.push(playerId);
                continue;
            }

            try {
                const ballPos = ball.location;
                if (!ballPos) {
                    this.returnToPlayer(playerId);
                    trackersToRemove.push(playerId);
                    continue;
                }

                // Calculate dynamic camera position based on ball movement
                const velocity = this.getBallVelocity(ball);
                const speed = Math.sqrt(velocity.x * velocity.x + velocity.y * velocity.y + velocity.z * velocity.z);
                
                // Dynamic camera positioning from reference code
                let cameraDistance = Math.max(5, Math.min(15, speed * 3));
                let cameraHeight = Math.max(3, Math.min(8, speed * 2 + 2));
                
                // Calculate camera position using precise coordinates from reference
                const ball_x = Math.round(ballPos.x);
                const ball_y = Math.round(ballPos.y) + 4; // +4 for better viewing angle
                const ball_z = Math.round(ballPos.z);
                
                let cameraPos = { x: ball_x, y: ball_y, z: ball_z };
                let facingPos = { x: ballPos.x, y: ballPos.y, z: ballPos.z };
                
                if (speed > 0.1) {
                    // Position camera behind movement direction with precise offset
                    const normalizedVel = {
                        x: -velocity.x / speed,
                        y: 0,
                        z: -velocity.z / speed
                    };
                    
                    cameraPos.x = ballPos.x + (normalizedVel.x * cameraDistance);
                    cameraPos.y = ballPos.y + cameraHeight;
                    cameraPos.z = ballPos.z + (normalizedVel.z * cameraDistance);
                } else {
                    // Default overhead view when ball is stationary
                    cameraPos.x = ballPos.x;
                    cameraPos.y = ballPos.y + 6;
                    cameraPos.z = ballPos.z - 8;
                }

                // Set camera using the modern API approach
                this.setCameraPosition(player, cameraPos, ballPos);
                
                // Check if ball has landed
                if (speed < 0.15) {
                    tracker.stationaryTicks++;
                    if (tracker.stationaryTicks > 10 && !tracker.ballLanded) {
                        tracker.ballLanded = true;
                        tracker.landTime = currentTick;
                    }
                } else {
                    tracker.stationaryTicks = 0;
                }
                
                // Return camera after ball has been stationary for 3 seconds (60 ticks)
                if (tracker.ballLanded && (currentTick - tracker.landTime) > 60) {
                    this.returnToPlayer(playerId);
                    trackersToRemove.push(playerId);
                }
                
                // Safety timeout - return camera after 15 seconds regardless
                if ((currentTick - tracker.trackingStartTime) > 300) {
                    this.returnToPlayer(playerId);
                    trackersToRemove.push(playerId);
                }
                
            } catch (error) {
                this.returnToPlayer(playerId);
                trackersToRemove.push(playerId);
            }
        }

        // Clean up removed trackers
        for (const playerId of trackersToRemove) {
            this.activeTrackers.delete(playerId);
        }
    }

    getBallVelocity(ball) {
        try {
            return ball.getVelocity() || { x: 0, y: 0, z: 0 };
        } catch (e) {
            return { x: 0, y: 0, z: 0 };
        }
    }

    setCameraPosition(player, cameraPos, targetPos) {
        try {
            // Use precise camera positioning from reference code
            const cmd = `camera @s set minecraft:free ease 0.15 linear pos ${cameraPos.x.toFixed(2)} ${cameraPos.y.toFixed(2)} ${cameraPos.z.toFixed(2)} facing ${targetPos.x.toFixed(2)} ${targetPos.y.toFixed(2)} ${targetPos.z.toFixed(2)}`;
            // console.log(`Camera: Executing command: ${cmd}`);
            player.runCommand(cmd);
            // console.log("Camera: Command executed successfully");
        } catch (error) {
            // console.warn("Camera: Primary command failed", error);
            // Fallback: try basic camera command
            try {
                const fallbackCmd = `camera @s set minecraft:free pos ${cameraPos.x.toFixed(2)} ${cameraPos.y.toFixed(2)} ${cameraPos.z.toFixed(2)}`;
                // console.log(`Camera: Trying fallback command: ${fallbackCmd}`);
                player.runCommand(fallbackCmd);
                // console.log("Camera: Fallback command executed successfully");
            } catch (fallbackError) {
                // console.error("Camera: Both commands failed", fallbackError);
            }
        }
    }

    returnToPlayer(playerId) {
        const tracker = this.activeTrackers.get(playerId);
        if (!tracker) {
            // console.log("Camera: No tracker found for player ID", playerId);
            return;
        }

        const { player } = tracker;
        if (!player) {
            // console.log("Camera: No player found in tracker");
            return;
        }

        // console.log(`Camera: Attempting to return camera for player ${player.name}`);
        
        // Use proper first person return - clear camera completely
        try {
            // First clear any active camera
            player.runCommand('camera @s clear');
            
            // Then reset to first person by setting camera to player's eyes
            const playerPos = player.location;
            const rotation = player.getRotation();
            // if (playerPos && rotation) {
                // Set camera to player's eye level (Y + 1.62 for eye height)
                const eyeHeight = 1.62;
                player.runCommand(`camera @s set minecraft:first_person`);

                system.runTimeout(() => {
                    player.runCommand('camera @s clear');
                }, 10);
                // console.log("Camera: Successfully returned to first person perspective");
                // player.sendMessage("§aCamera returned to normal view!");
            // } else {
            //     // Simple clear fallback
            //     player.runCommand('camera @s clear');
            //     // console.log("Camera: Returned using clear command");
            // }
        } catch (error) {
            // console.error("Camera: Failed to return to first person", error);
            // Ultimate fallback - clear camera
            try {
                player.runCommand('camera @s clear');
                // console.log("Camera: Successfully cleared camera");
            } catch (clearError) {
                // console.error("Camera: All return attempts failed", clearError);
            }
        }
    }

    stopTracking(playerId) {
        if (this.activeTrackers.has(playerId)) {
            this.returnToPlayer(playerId);
            this.activeTrackers.delete(playerId);
        }
    }

    forceStopTracking(player) {
        if (player && player.id) {
            this.stopTracking(player.id);
        }
    }

    isPlayerTracking(player) {
        return player && player.id && this.activeTrackers.has(player.id);
    }

    // Clean up method
    cleanup() {
        // Return all players to normal view
        for (const [playerId] of this.activeTrackers) {
            this.returnToPlayer(playerId);
        }
        this.activeTrackers.clear();
        
        if (this.updateInterval) {
            system.clearRun(this.updateInterval);
            this.updateInterval = null;
        }
    }
}

// Create and export the camera system instance
export const golfCameraSystem = new GolfCameraSystem();