// Golf System Utility Functions
// Contains helper functions for calculations, physics, and common operations

import { PHYSICS, TRAIL_SETTINGS, PARTICLES, SOUNDS } from './config.js';

const debugging = false;

export function debug(type, message) {
    if (debugging) {
        switch (type) {
            case 'info':
                console.log(`[§2Golf] ${message}`);
                break;
            case 'error':
                console.error(`[§4Golf] ${message}`);
                break;
            case 'warn':
                console.warn(`[§6Golf] ${message}`);
                break;
            case 'verbose':
                console.log(`[§8Golf][V] ${message}`);
                break;
            default:
                console.log(`[§2Golf] ${message}`);
                break;
        }
    }
}

/**
 * Calculate the look direction vector from player's yaw and pitch
 * @param {Player} player - The player entity
 * @returns {Object} Direction vector {x, y, z}
 */
export function getLookDirection(player) {
    const rotation = player.getRotation();
    const pitch = rotation.x * (Math.PI / 180); // up/down
    const yaw = rotation.y * (Math.PI / 180);   // left/right

    // Minecraft coordinate system: x = east/west, y = up/down, z = south/north
    const x = -Math.sin(yaw) * Math.cos(pitch);
    const y = -Math.sin(pitch);
    const z = Math.cos(yaw) * Math.cos(pitch);

    return { x, y, z };
}

/**
 * Calculate 3D distance between two positions
 * @param {Object} pos1 - First position {x, y, z}
 * @param {Object} pos2 - Second position {x, y, z}
 * @returns {number} Distance in blocks
 */
export function calculateDistance(pos1, pos2) {
    return Math.sqrt(
        Math.pow(pos1.x - pos2.x, 2) +
        Math.pow(pos1.y - pos2.y, 2) +
        Math.pow(pos1.z - pos2.z, 2)
    );
}

/**
 * Calculate 2D horizontal distance (ignoring Y coordinate)
 * @param {Object} pos1 - First position {x, z}
 * @param {Object} pos2 - Second position {x, z}
 * @returns {number} Horizontal distance in blocks
 */
export function calculateHorizontalDistance(pos1, pos2) {
    return Math.sqrt(
        Math.pow(pos1.x - pos2.x, 2) +
        Math.pow(pos1.z - pos2.z, 2)
    );
}

/**
 * Check if a position is within world boundaries
 * @param {Object} position - Position to check {x, y, z}
 * @returns {boolean} True if within bounds
 */
export function isWithinWorldBounds(position) {
    return (
        position.x >= PHYSICS.WORLD_MIN && position.x <= PHYSICS.WORLD_MAX &&
        position.y >= PHYSICS.MIN_Y && position.y <= PHYSICS.MAX_Y &&
        position.z >= PHYSICS.WORLD_MIN && position.z <= PHYSICS.WORLD_MAX
    );
}

/**
 * Clamp velocity to safe values to prevent world boundary issues
 * @param {number} velocity - Velocity component to clamp
 * @returns {number} Clamped velocity
 */
export function clampVelocity(velocity) {
    return Math.min(Math.max(velocity, -PHYSICS.MAX_VELOCITY), PHYSICS.MAX_VELOCITY);
}

/**
 * Calculate relative direction from player to target position
 * @param {Object} playerPos - Player position {x, z}
 * @param {Object} targetPos - Target position {x, z}
 * @param {number} playerYaw - Player's yaw rotation in degrees
 * @returns {string} Direction symbol (↑, ↗, →, ↘, ↓, ↙, ←, ↖)
 */
export function getRelativeDirection(playerPos, targetPos, playerYaw) {
    // Calculate direction vector from player to target
    const dx = targetPos.x - playerPos.x;
    const dz = targetPos.z - playerPos.z;
    
    // Calculate angle relative to player's facing direction
    const playerYawRad = playerYaw * (Math.PI / 180);
    const playerDx = -Math.sin(playerYawRad);
    const playerDz = Math.cos(playerYawRad);
    
    // Dot product and cross product to get relative angle
    const dot = dx * playerDx + dz * playerDz;
    const cross = dx * playerDz - dz * playerDx;
    
    let angle = Math.atan2(cross, dot) * (180 / Math.PI);
    if (angle < 0) angle += 360;
    
    // Convert to cardinal directions using symbols
    if (angle >= 337.5 || angle < 22.5) return "§a↑";
    else if (angle >= 22.5 && angle < 67.5) return "§a↖";
    else if (angle >= 67.5 && angle < 112.5) return "§a←";
    else if (angle >= 112.5 && angle < 157.5) return "§a↙";
    else if (angle >= 157.5 && angle < 202.5) return "§a↓";
    else if (angle >= 202.5 && angle < 247.5) return "§a↘";
    else if (angle >= 247.5 && angle < 292.5) return "§a→";
    else return "§a↗";
}

/**
 * Play sound with fallback options
 * @param {Dimension} dimension - The dimension to play sound in
 * @param {string} primarySound - Primary sound to attempt
 * @param {string} fallbackSound - Fallback sound if primary fails
 * @param {Object} location - Location to play sound at
 * @param {Object} options - Sound options (volume, pitch, etc.)
 */
export function playSoundWithFallback(dimension, primarySound, fallbackSound, location, options = {}) {
    try {
        dimension.playSound(primarySound, location, options);
    } catch (error) {
        try {
            dimension.playSound(fallbackSound, location, options);
        } catch (fallbackError) {
            console.warn(`Failed to play both primary (${primarySound}) and fallback (${fallbackSound}) sounds`);
        }
    }
}

/**
 * Spawn particle with fallback options
 * @param {Dimension} dimension - The dimension to spawn particle in
 * @param {Object} location - Location to spawn particle at
 * @param {Object} offset - Optional offset for randomization
 */
export function spawnParticleWithFallback(dimension, location, offset = {}) {
    const finalLocation = {
        x: location.x + (offset.x || 0),
        y: location.y + (offset.y || 0),
        z: location.z + (offset.z || 0)
    };

    try {
        dimension.spawnParticle(PARTICLES.PRIMARY, finalLocation);
    } catch (error) {
        try {
            dimension.spawnParticle(PARTICLES.FALLBACK_1, finalLocation);
        } catch (e) {
            try {
                dimension.spawnParticle(PARTICLES.FALLBACK_2, finalLocation);
            } catch (final) {
                // Silently fail if all particles fail
            }
        }
    }
}

/**
 * Create randomized offset for particle effects
 * @param {number} range - Range for randomization
 * @returns {Object} Offset {x, y, z}
 */
export function createRandomOffset(range = TRAIL_SETTINGS.TRAIL_OFFSET_RANGE) {
    return {
        x: (Math.random() - 0.5) * range,
        y: (Math.random() - 0.5) * (range * 0.5),
        z: (Math.random() - 0.5) * range
    };
}

/**
 * Check if a player is looking at a specific entity
 * @param {Player} player - The player
 * @param {Entity} entity - The entity to check
 * @param {number} threshold - Dot product threshold (default 0.85 for ~30 degrees)
 * @returns {boolean} True if player is looking at entity
 */
export function isPlayerLookingAtEntity(player, entity, threshold = 0.85) {
    const lookDirection = getLookDirection(player);
    const playerPos = player.location;
    const entityPos = entity.location;
    
    // Calculate direction from player to entity
    const direction = {
        x: entityPos.x - playerPos.x,
        y: entityPos.y - playerPos.y,
        z: entityPos.z - playerPos.z
    };
    
    const distance = Math.sqrt(direction.x * direction.x + direction.y * direction.y + direction.z * direction.z);
    if (distance === 0) return false;
    
    // Normalize direction vector
    direction.x /= distance;
    direction.y /= distance;
    direction.z /= distance;
    
    // Calculate dot product
    const dotProduct = direction.x * lookDirection.x + direction.y * lookDirection.y + direction.z * lookDirection.z;
    
    return dotProduct > threshold;
}

/**
 * Find the closest entity from a list to a reference position
 * @param {Array} entities - Array of entities to search
 * @param {Object} referencePos - Reference position {x, y, z}
 * @returns {Object|null} Closest entity or null if none found
 */
export function findClosestEntity(entities, referencePos) {
    if (!entities || entities.length === 0) return null;
    
    let closestEntity = null;
    let minDistance = Infinity;
    
    for (const entity of entities) {
        const distance = calculateDistance(entity.location, referencePos);
        if (distance < minDistance) {
            minDistance = distance;
            closestEntity = entity;
        }
    }
    
    return closestEntity;
}

/**
 * Validate and parse form response values
 * @param {Array} formValues - Raw form values from ModalFormData
 * @returns {Array} Validated and parsed values
 */
export function validateFormValues(formValues) {
    if (!Array.isArray(formValues)) return [];
    
    return formValues.map(value => {
        if (typeof value === "number") return value;
        if (typeof value === "string") {
            const parsed = parseInt(value, 10);
            return !isNaN(parsed) ? parsed : 0;
        }
        return 0;
    });
}