// Golf System Scoring and Ledger Management
// Contains scoring logic, ledger operations, and ball location tracking

import { world, system, EntityComponentTypes } from "@minecraft/server";
import { ActionFormData, ModalFormData } from "@minecraft/server-ui";
import { LEDGER_ID, SCORING, BALL_TRACKING, GOLFBALL_ID, GOLFTRAILS, GOLFBALL_SPAWN_EGG_ID } from './config.js';
import { calculateHorizontalDistance, getRelativeDirection, findClosestEntity } from './utils.js';
import {
    getPlayerSwingCount,
    setPlayerSwingCount,
    incrementPlayerSwingCount,
    resetPlayerSwingCount,
    getPlayerCurrentRound,
    setPlayerCurrentRound,
    addHoleToCurrentRound,
    clearPlayerCurrentRound,
    getPlayerActiveBallId,
    setPlayerActiveBallId,
    getPlayerGamemode as getPersistentPlayerGamemode,
    setPlayerGamemode as setPersistentPlayerGamemode,
    getPlayerParticlePreference as getPersistentPlayerParticlePreference,
    setPlayerParticlePreference as setPersistentPlayerParticlePreference,
    getPlayerReturnTimePreference as getPersistentPlayerReturnTimePreference,
    setPlayerReturnTimePreference as setPersistentPlayerReturnTimePreference,
    getPlayerCameraTrackingPreference as getPersistentPlayerCameraTrackingPreference,
    setPlayerCameraTrackingPreference as setPersistentPlayerCameraTrackingPreference,
    getPlayerClubOptions as getPersistentPlayerClubOptions,
    setPlayerClubOptions as setPersistentPlayerClubOptions,
    clearPlayerClubOptions as clearPersistentPlayerClubOptions,
    clearAllPlayerGolfData,
    migrateMapDataToWorldProperties
} from './persistence.js';

// Global state for scoring (session-only data that doesn't need persistence)
const playerScoreboards = new Map(); // Track scoreboard objects per player
let scoreboardVisibility = true; // Track if scoreboard is visible
const ballLocationTracking = new Map(); // Track which players have active ball location display
export const playerIntervals = new Map(); // Track intervals for ball location updates
const ballReturnTimers = new Map(); // Track ball return timers for driving range mode

// Migration flag to ensure we only migrate once
let migrationCompleted = false;

// Legacy Maps for migration purposes (will be removed after migration)
const legacyPlayerSwingCount = new Map();
const legacyCurrentRoundData = new Map();
const legacyPlayerGamemodes = new Map();
const legacyPlayerParticlePreferences = new Map();
const legacyPlayerReturnTimePreferences = new Map();
const legacyPlayerCameraTrackingPreferences = new Map();

/**
 * Perform one-time migration from Maps to world dynamic properties
 */
function performMigration() {
    // console.log("Performing golf data migration from Maps to world dynamic properties...");
    
    // Since this is a new implementation, we don't have existing Map data to migrate
    // This function is here for future use if needed
    // The persistence system will handle new data automatically
    
    // console.log("Migration completed - using persistent storage for all new data.");
}

/**
 * Get flavorful stroke description based on number of strokes
 * @param {number} strokes - Number of strokes taken
 * @returns {string} Formatted flavor text
 */
export function djjawhda(strokes) {
    const flavors = {
        1: "§eHole-in-one! Absolutely legendary!",
        2: "§aEagle! Exceptional precision!",
        3: "§aBirdie! Well played!",
        4: "§7Par. Solid performance.",
        5: "§6Bogey. Room for improvement.",
        6: "§6Double bogey. Keep practicing!",
        7: "§cTriple bogey. The course won this round.",
        8: "§cQuadruple bogey. Ouch! That's rough.",
        9: "§cQuintuple bogey. The ball had a mind of its own...",
        10: "§cDecuple bogey+. Perhaps consider a mulligan?"
    };
    
    return flavors[strokes] || `§c${strokes} strokes. Epic saga continues...`;
}

/**
 * Create or get player-specific scoreboard
 * @param {Player} player - The player
 * @returns {ScoreboardObjective} Player's scoreboard
 */
function getPlayerScoreboard(player) {
    const scoreboardId = `golf_${player.name.toLowerCase().replace(/[^a-z0-9]/g, '_')}`;
    let scoreboard = playerScoreboards.get(player.id);
    
    if (!scoreboard) {
        try {
            // Try to get existing scoreboard
            scoreboard = world.scoreboard.getObjective(scoreboardId);
            if (scoreboard) {
                playerScoreboards.set(player.id, scoreboard);
            }
        } catch (error) {
            // Scoreboard doesn't exist, create new one
            scoreboard = null;
        }
        
        if (!scoreboard) {
            try {
                // Create new scoreboard
                scoreboard = world.scoreboard.addObjective(scoreboardId, `§b${player.name}'s Golf`);
                playerScoreboards.set(player.id, scoreboard);
            } catch (error) {
                console.warn(`Failed to create scoreboard for ${player.name}:`, error);
                return null;
            }
        }
    }
    
    return scoreboard;
}

/**
 * Update player's scoreboard with current round info
 * @param {Player} player - The player
 */
function updatePlayerScoreboard(player) {
    const scoreboard = getPlayerScoreboard(player);
    if (!scoreboard) {
        console.warn(`Failed to get scoreboard for player ${player.name}`);
        return;
    }
    
    const swings = getPlayerSwingCount(player.id);
    const roundData = getPlayerCurrentRound(player.id);
    
    // Clear existing scores
    try {
        const participants = scoreboard.getParticipants();
        participants.forEach(participant => {
            scoreboard.removeParticipant(participant);
        });
    } catch (error) {
        // Ignore if no participants
    }
    
    // Add current round info
    try {
        scoreboard.setScore("§7Current Strokes", swings);
        scoreboard.setScore("§7Holes Completed", roundData.holes.length);
        
        // Show scoreboard to player
        player.runCommand(`scoreboard objectives setdisplay sidebar ${scoreboard.id}`);
    } catch (error) {
        console.warn(`Failed to update scoreboard for ${player.name}:`, error);
    }
}

/**
 * Save round data to world dynamic properties
 * @param {Player} player - The player
 * @param {Object} roundData - Round data to save
 */
function saveRoundData(player, roundData) {
    const playerId = player.id;
    const savedRounds = world.getDynamicProperty(`golf_rounds_${playerId}`) || "[]";
    
    try {
        const rounds = JSON.parse(savedRounds);
        rounds.push({
            ...roundData,
            endTime: Date.now(),
            playerName: player.name
        });
        
        // Keep only last 50 rounds to prevent data bloat
        if (rounds.length > 50) {
            rounds.splice(0, rounds.length - 50);
        }
        
        world.setDynamicProperty(`golf_rounds_${playerId}`, JSON.stringify(rounds));
    } catch (error) {
        console.warn(`Failed to save round data for ${player.name}:`, error);
    }
}

/**
 * Get saved round data for a player
 * @param {Player} player - The player
 * @returns {Array} Array of saved rounds
 */
function getSavedRounds(player) {
    const playerId = player.id;
    const savedRounds = world.getDynamicProperty(`golf_rounds_${playerId}`) || "[]";
    
    try {
        return JSON.parse(savedRounds);
    } catch (error) {
        console.warn(`Failed to load round data for ${player.name}:`, error);
        return [];
    }
}

/**
 * Update scoring when hole is completed
 * @param {Player} player - The player who completed the hole
 * @param {number} swings - Number of swings taken
 * @param {Object} holeLocation - Hole coordinates {x, y, z}
 */
export function updateLedger(player, swings, holeLocation = null) {
    // Add hole to current round
    const holeData = {
        strokes: swings,
        completedAt: Date.now(),
        flavor: djjawhda(swings),
        location: holeLocation || { x: 0, y: 0, z: 0 }
    };
    
    addHoleToCurrentRound(player.id, holeData);
    const roundData = getPlayerCurrentRound(player.id);
    
    // Update player's scoreboard
    updatePlayerScoreboard(player);
    
    // Announce score to all players
    const announcement = `§7[§bGolf§7] §e${player.name} §7completed hole §a${roundData.holes.length} §7with §e${swings} §7strokes! ${djjawhda(swings)}`;
    world.getAllPlayers().forEach(p => {
        p.sendMessage(announcement);
    });
    
    player.onScreenDisplay.setActionBar(`§bHole completed! Round: ${roundData.holes.length} holes`);
}

/**
 * Show ledger UI with all options
 * @param {Player} player - The player to show UI to
 */
export function showLedgerUI(player) {
    const swings = getPlayerSwingCount(player.id);
    const roundData = getPlayerCurrentRound(player.id);
    const isScoreboardVisible = scoreboardVisibility;
    
    const currentGamemode = getPlayerGamemode(player.id);
    const isCameraTrackingEnabled = getPlayerCameraTrackingPreference(player.id);
    const particleTrail = GOLFTRAILS[getPlayerParticlePreference(player.id).split("dss_gep:dss_gep_")[1].split("_trail")[0]];
    const particlePreference = particleNames[getPlayerParticlePreference(player.id)]
    const returnTime = getPlayerReturnTimePreference(player.id);
    const returnTimeIcon = `textures/dss/gep/icons/stmr${returnTime}_icon`;
    const locatorActive = ballLocationTracking.get(player.id) || false;
    
    const form = currentGamemode === 'golf_course' ? 
        new ActionFormData()
        .title("§8Golf Ledger")
        .body(`§7Current Round Info:\n§fStrokes: §e${swings}\n§fHoles Completed: §e${roundData.holes.length}\n§fRound Duration: §e${Math.floor((Date.now() - roundData.startTime) / 60000)} min`)
        .button("§vRound and History", "textures/dss/gep/icons/shst_icon.png")
        .button(`${locatorActive ? '§2Locating Golf Ball\n§8Click to Disable' : '§uNot Locating Golf Ball\n§8Click to Enable'}`, "textures/dss/gep/icons/slct_icon.png")
        .button(`${isCameraTrackingEnabled ? '§2Enabled Ball Camera Track\n§8Click to Disable' : '§cDisabled Ball Camera Track\n§8Click to Enable'}`, `${isCameraTrackingEnabled ? "textures/dss/gep/icons/scmr_icon.png" : "textures/dss/gep/icons/scmrn_icon.png"}`)
        .button(particlePreference + " Trail" + "\n§8Click to Change", `${particleTrail}`)
        .button("§5Reset Golfball", "textures/dss/gep/icons/srst_icon.png")
        .button("§8Mode: §2Golf Course\n§8Click to Change", "textures/dss/gep/icons/sgmd2_icon.png")
        .button(`§${isScoreboardVisible ? 'c' : '2'}${isScoreboardVisible ? 'Hide' : 'Show'} Scoreboard`, "textures/dss/gep/icons/sscr_icon.png")
        .button("§cClear Data", "textures/ui/trash")
        :
        new ActionFormData()
        .title("§8Golf Ledger")
        .body(`§7Current Round Info:\n§fStrokes: §e${swings}\n§fHoles Completed: §e${roundData.holes.length}\n§fRound Duration: §e${Math.floor((Date.now() - roundData.startTime) / 60000)} min`)
        .button(`${locatorActive ? '§2Locating Golf Ball\n§8Click to Disable' : '§uNot Locating Golf Ball\n§8Click to Enable'}`, "textures/dss/gep/icons/slct_icon.png")
        .button("§9Golfball Return Time", `${returnTimeIcon}`)
        .button(`${isCameraTrackingEnabled ? '§2Enabled Ball Camera Track\n§8Click to Disable' : '§cDisabled Ball Camera Track\n§8Click to Enable'}`, `${isCameraTrackingEnabled ? "textures/dss/gep/icons/scmr_icon.png" : "textures/dss/gep/icons/scmrn_icon.png"}`)
        .button(particlePreference + " Trail" + "\n§8Click to Change", `${particleTrail}`)
        .button("§8Mode: §uDriving Range\n§8Click to Change", "textures/dss/gep/icons/sgmd1_icon.png")
        .button(`§${isScoreboardVisible ? 'c' : '2'}${isScoreboardVisible ? 'Hide' : 'Show'} Scoreboard`, "textures/dss/gep/icons/sscr_icon.png")
        .button("§cClear Data", "textures/ui/trash");

    
    form.show(player).then(response => {
        if (response.canceled) return;
        
        if (currentGamemode === 'golf_course') {
            switch (response.selection) {
                case 0: // History
                    showHistory(player);
                    break;
                case 1: // Toggle Camera Tracking
                    const isActive = toggleBallLocation(player);
                    if (isActive) {
                        player.sendMessage("§aBall location tracking enabled");
                    } else {
                        player.sendMessage("§7Ball location tracking disabled");
                    }
                    break;
                case 2: // Locate Golfball
                    toggleCameraTracking(player);
                    break;
                case 3: // Particle Trail
                    showParticleSelection(player);
                    break;
                case 4: // Reset Golfball
                    resetGolfball(player);
                    break;
                case 5: // Select Gamemode
                    showGamemodeSelection(player);
                    break;
                case 6: // Toggle Scoreboard
                    toggleScoreboard(player);
                    break;
                case 7: // Reset Data
                    showResetDataConfirmation(player);
                    break;
            }
        } else {
            switch (response.selection) {
                case 0: // Locate Golfball
                    const isActive = toggleBallLocation(player);
                    if (isActive) {
                        player.sendMessage("§aBall location tracking enabled");
                    } else {
                        player.sendMessage("§7Ball location tracking disabled");
                    }
                    break;
                case 1: // Return Time
                    showReturnTimeSelection(player);
                    break;
                case 2: // Toggle Camera Tracking
                    toggleCameraTracking(player);
                    break;
                case 3: // Particle Trail
                    showParticleSelection(player);
                    break;
                case 4: // Select Gamemode
                    showGamemodeSelection(player);
                    break;
                case 5: // Toggle Scoreboard
                    toggleScoreboard(player);
                    break;
                case 6: // Reset Data
                    showResetDataConfirmation(player);
                    break;
            }
        }
    });
}

/**
 * Toggle scoreboard visibility for player
 * @param {Player} player - The player
 */
function toggleScoreboard(player) {
    const isVisible = scoreboardVisibility;
    
    if (isVisible) {
        // Hide scoreboard
        player.runCommand("scoreboard objectives setdisplay sidebar");
        scoreboardVisibility = false;
        world.sendMessage("§7Scoreboard hidden");
    } else {
        // Show scoreboard
        updatePlayerScoreboard(player);
        scoreboardVisibility = true;
        world.sendMessage("§aScoreboard displayed");
    }
}

/**
 * Reset player's golfball (remove current ball and give new spawn egg)
 * @param {Player} player - The player
 */
function resetGolfball(player) {
    // Find and remove player's current golf ball
    const golfballs = player.dimension.getEntities({ type: GOLFBALL_ID });
    let ballRemoved = false;
    
    for (const ball of golfballs) {
        const owner = ball.getDynamicProperty("owner");
        if (owner === player.name) {
            ball.remove();
            ballRemoved = true;
            break;
        }
    }
    
    if (ballRemoved) {
        // Give new spawn egg only if ball was found and removed
        player.runCommand(`give @s ${GOLFBALL_SPAWN_EGG_ID}`);
        player.onScreenDisplay.setActionBar("§aGolf ball reset! New spawn egg given.");
    } else {
        player.onScreenDisplay.setActionBar("§cNo active golf ball found to reset.");
    }
}

/**
 * Show confirmation dialog for resetting all data
 * @param {Player} player - The player
 */
function showResetDataConfirmation(player) {
    const form = new ModalFormData()
        .title("§cConfirm Data Reset")
        .textField("Type 'CONFIRM' to reset all golf data:", "CONFIRM")
        .toggle("I understand this will delete all my golf history");
    
    form.show(player).then(response => {
        if (response.canceled) return;
        
        const [confirmText, confirmToggle] = response.formValues;
        if (confirmText === "CONFIRM" && confirmToggle) {
            resetAllData(player);
        } else {
            player.onScreenDisplay.setActionBar("§cData reset cancelled - confirmation requirements not met.");
        }
    });
}

/**
 * Reset all golf data for a player
 * @param {Player} player - The player
 */
function resetAllData(player) {
    // Clear all persistent golf data
    clearAllPlayerGolfData(player.id);
    
    // Remove scoreboard
    const scoreboard = playerScoreboards.get(player.id);
    if (scoreboard) {
        try {
            world.scoreboard.removeObjective(scoreboard.id);
        } catch (error) {
            // Ignore if scoreboard doesn't exist
        }
        playerScoreboards.delete(player.id);
    }
    
    // Clear ball location tracking
    ballLocationTracking.delete(player.id);
    const intervalId = playerIntervals.get(player.id);
    if (intervalId) {
        system.clearRun(intervalId);
        playerIntervals.delete(player.id);
    }
    
    // Camera tracking preference is now handled by clearAllPlayerGolfData()
    
    // Announce to all players
    const announcement = `§7[§bGolf§7] §e${player.name} §7has reset their golf data and started fresh!`;
    world.getAllPlayers().forEach(p => {
        p.sendMessage(announcement);
    });
    
    player.onScreenDisplay.setActionBar("§a§lAll Golf Data Reset!§r\n§7Your golf history, scores, and settings have been cleared.");
    player.onScreenDisplay.setActionBar("§7Ready for a fresh start!");
}

/**
 * Show score history for a player
 * @param {Player} player - The player to show history for
 */
export function showHistory(player) {
    const savedRounds = getSavedRounds(player);
    const currentRound = getPlayerCurrentRound(player.id);
    const swingCount = getPlayerSwingCount(player.id);
    
    let historyText = `§e§lGolf History for ${player.name}§r\n\n`;
    
    // Current round info
    historyText += `§b§lCurrent Round:§r\n`;
    historyText += `§7Current Strokes: §f${swingCount}\n`;
    historyText += `§7Holes Completed: §f${currentRound.holes.length}\n`;
    historyText += `§7Round Duration: §f${Math.floor((Date.now() - currentRound.startTime) / 60000)} minutes\n\n`;
    
    if (currentRound.holes.length > 0) {
        historyText += `§7Recent Holes:\n`;
        const recentHoles = currentRound.holes.slice(-3);
        const startHoleNum = Math.max(1, currentRound.holes.length - recentHoles.length + 1);
        recentHoles.forEach((hole, index) => {
            const holeNum = startHoleNum + index;
            historyText += `§2${holeNum}. §7${hole.strokes} ${hole.strokes > 1 ? 'strokes' : 'stroke'} §8(${hole.flavor.replace(/§[0-9a-f]/g, '')})\n`;
        });
        historyText += `\n`;
    }
    
    // Previous rounds
    if (savedRounds.length > 0) {
        historyText += `§a§lPrevious Rounds (Last 5):§r\n`;
        const recentRounds = savedRounds.slice(-5);
        const startRoundNum = Math.max(1, savedRounds.length - recentRounds.length + 1);
        recentRounds.forEach((round, index) => {
            const roundNum = startRoundNum + index;
            const totalStrokes = round.holes.reduce((sum, hole) => sum + hole.strokes, 0);
            const avgStrokes = (totalStrokes / round.holes.length).toFixed(1);
            const duration = Math.floor((round.endTime - round.startTime) / 60000);
            
            historyText += `§3${roundNum}. §7${round.holes.length} holes, ${totalStrokes} total strokes (avg: ${avgStrokes})\n`;
            historyText += `§8   Duration: ${duration} min, Completed: ${new Date(round.endTime).toLocaleString()}\n`;
        });
    } else {
        historyText += `§7No previous rounds recorded.\n`;
    }
    
    // Show in form for better readability
    const form = new ActionFormData()
        .title("§eGolf History")
        .body(historyText)
        .button("§aFinish Current Round", "textures/ui/check")
        .button("§cClose", "textures/ui/cancel");
    
    form.show(player).then(response => {
        if (response.canceled || response.selection === 1) return;
        
        if (response.selection === 0) {
            // Finish current round
            finishCurrentRound(player);
        }
    });
}

/**
 * Finish current round and save to history
 * @param {Player} player - The player
 */
function finishCurrentRound(player) {
    const roundData = getPlayerCurrentRound(player.id);
    
    if (!roundData || roundData.holes.length === 0) {
        player.onScreenDisplay.setActionBar("§cNo active round to finish!");
        return;
    }
    
    // Save round data
    saveRoundData(player, roundData);
    
    // Clear current round
    clearPlayerCurrentRound(player.id);
    resetPlayerSwingCount(player.id);
    
    // Update scoreboard
    updatePlayerScoreboard(player);
    
    const totalStrokes = roundData.holes.reduce((sum, hole) => sum + hole.strokes, 0);
    const avgStrokes = (totalStrokes / roundData.holes.length).toFixed(1);
    
    player.sendMessage(`§a§lRound Finished!§r`);
    player.sendMessage(`§7Holes: §f${roundData.holes.length}`);
    player.sendMessage(`§7Total Strokes: §f${totalStrokes}`);
    player.sendMessage(`§7Average: §f${avgStrokes} strokes per hole`);
    player.sendMessage(`§7Duration: §f${Math.floor((Date.now() - roundData.startTime) / 60000)} minutes`);
}

/**
 * Toggle ball location display for a player
 * @param {Player} player - The player to toggle tracking for
 * @returns {boolean} True if tracking was enabled, false if disabled
 */
export function toggleBallLocation(player) {
    const isActive = ballLocationTracking.get(player.id) || false;
    
    if (isActive) {
        // Turn off ball location
        ballLocationTracking.delete(player.id);
        
        // Clear the interval for this player
        const intervalId = playerIntervals.get(player.id);
        if (intervalId) {
            system.clearRun(intervalId);
            playerIntervals.delete(player.id);
        }
        
        player.onScreenDisplay.setActionBar("§7Ball location tracking disabled");
        return false;
    } else {
        // Turn on ball location
        ballLocationTracking.set(player.id, true);
        
        // Start interval for continuous display
        const intervalId = system.runInterval(() => {
            updateBallLocationDisplay(player);
        }, BALL_TRACKING.UPDATE_INTERVAL_TICKS);
        
        playerIntervals.set(player.id, intervalId);
        updateBallLocationDisplay(player);
        return true;
    }
}

/**
 * Continuously update ball location display for a player
 * @param {Player} player - The player to update display for
 */
export function updateBallLocationDisplay(player) {
    const isActive = ballLocationTracking.get(player.id) || false;
    if (!isActive) return;
    
    const ownedBalls = player.dimension.getEntities({ 
        type: "dss_nocturne:dss_normal_golfball", // Using direct ID since config import might cause circular dependency
        location: player.location,
        maxDistance: BALL_TRACKING.MAX_SEARCH_DISTANCE
    }).filter(entity => {
        const owner = entity.getDynamicProperty("owner");
        return owner === player.name;
    });
    
    if (ownedBalls.length === 0) {
        player.onScreenDisplay.setActionBar("§7No owned golf balls found nearby.");
        ballLocationTracking.delete(player.id);
        
        // Clear the interval for this player
        const intervalId = playerIntervals.get(player.id);
        if (intervalId) {
            system.clearRun(intervalId);
            playerIntervals.delete(player.id);
        }
        return;
    }
    
    // Find the closest owned golf ball
    const closestBall = findClosestEntity(ownedBalls, player.location);
    
    if (closestBall) {
        // Calculate relative direction to ball based on player facing
        const ballPos = closestBall.location;
        const playerPos = player.location;
        const playerRotation = player.getRotation();
        
        const distance = Math.floor(calculateHorizontalDistance(playerPos, ballPos));
        
        if (distance === 0) {
            // Player is on top of the golf ball
            player.onScreenDisplay.setActionBar(`§a○ On Golf Ball`);
        } else {
            // Normal distance display with symbols
            const direction = getRelativeDirection(playerPos, ballPos, playerRotation.y);
            player.onScreenDisplay.setActionBar(`§b${distance} blocks ${direction} §7○ Golf Ball`);
        }
    }
}

/**
 * Handle ledger use - show main UI
 * @param {Player} player - The player who used the ledger
 */
export function handleLedgerClick(player) {
    // Perform one-time migration if needed
    if (!migrationCompleted) {
        performMigration();
        migrationCompleted = true;
    }
    
    // Initialize player data if first time using ledger (this will use defaults from persistence)
    const roundData = getPlayerCurrentRound(player.id);
    if (roundData.holes.length === 0 && !playerScoreboards.has(player.id)) {
        // Create and show scoreboard for new players
        updatePlayerScoreboard(player);
        player.onScreenDisplay.setActionBar("§aWelcome to Golf! Your scoreboard has been created.");
    }
    
    showLedgerUI(player);
}

/**
 * Increment swing count for a player and update their scoreboard
 * @param {string} playerId - The player's ID
 * @returns {number} New swing count
 */
export function incrementSwingCount(playerId) {
    const swings = incrementPlayerSwingCount(playerId);
    
    // Find the player and update their scoreboard
    const player = world.getAllPlayers().find(p => p.id === playerId);
    if (player) {
        updatePlayerScoreboard(player);
    }
    
    return swings;
}

/**
 * Reset swing count for a player and update their scoreboard
 * @param {string} playerId - The player's ID
 */
export function resetSwingCount(playerId) {
    resetPlayerSwingCount(playerId);
    
    // Find the player and update their scoreboard
    const player = world.getAllPlayers().find(p => p.id === playerId);
    if (player) {
        updatePlayerScoreboard(player);
    }
}

/**
 * Get current swing count for a player
 * @param {string} playerId - The player's ID
 * @returns {number} Current swing count
 */
export function getSwingCount(playerId) {
    return getPlayerSwingCount(playerId);
}

/**
 * Show gamemode selection UI
 * @param {Player} player - The player to show UI to
 */
function showGamemodeSelection(player) {
    const currentGamemode = getPlayerGamemode(player.id);
    
    const form = new ActionFormData()
        .title("§6Select Gamemode")
        .body("Choose your preferred golf experience:")
        .button("§2Golf Course\n§3Normal golf with hole detection", `${currentGamemode === 'golf_course' ? "textures/ui/check" : "textures/dss/gep/icons/sgmd2_icon.png"}`)
        .button("§5Driving Range\n§3Ball returns to you after a few seconds", `${currentGamemode === 'driving_range' ? "textures/ui/check" : "textures/dss/gep/icons/sgmd1_icon.png"}`);
    
    form.show(player).then(response => {
        if (response.canceled) return;
        
        switch (response.selection) {
            case 0: // Golf Course
                if (currentGamemode === 'golf_course') {
                    player.onScreenDisplay.setActionBar("§aYou are already in Golf Course mode!");
                    return;
                }
                setPersistentPlayerGamemode(player.id, 'golf_course');
                player.onScreenDisplay.setActionBar("§aSwitched to Golf Course mode!\n§7Play normal golf with hole detection.");
                break;
            case 1: // Driving Range
                if (currentGamemode === 'driving_range') {
                    player.onScreenDisplay.setActionBar("§aYou are already in Driving Range mode!");
                    return;
                }
                setPersistentPlayerGamemode(player.id, 'driving_range');
                player.onScreenDisplay.setActionBar("§aSwitched to Driving Range mode!\n§7Your golf ball will return to you after a few seconds.");
                break;
        }
    });
}

/**
 * Handle ball return for driving range mode
 * @param {Entity} golfball - The golf ball entity
 * @param {Player} player - The player who owns the ball
 */
export function handleDrivingRangeReturn(golfball, player) {
    if (!player || !golfball) return;
    
    const ballId = golfball.id;
    
    // Check if we already have a timer for this ball
    if (ballReturnTimers.has(ballId)) {
        return; // Already scheduled to return
    }
    
    // Get player's preferred return time (in seconds)
    const returnTimeSeconds = getPlayerReturnTimePreference(player.id);
    const ticksRemaining = Math.max(20, returnTimeSeconds * 20); // Convert seconds to ticks (min 1 second)
    
    let currentTick = 0;
    const timerId = system.runInterval(() => {
        currentTick++;
        
        if (currentTick >= ticksRemaining) {
            // Simple ball return without complex validation
            resetGolfball(player);
            player.onScreenDisplay.setActionBar(`§aBall returned to you after ${returnTimeSeconds} seconds!`);
            
            ballReturnTimers.delete(ballId);
            system.clearRun(timerId);
        }
    }, 1);
    
    ballReturnTimers.set(ballId, timerId);
}

/**
 * Get player's current gamemode
 * @param {string} playerId - The player's ID
 * @returns {string} Current gamemode ('golf_course' or 'driving_range')
 */
export function getPlayerGamemode(playerId) {
    return getPersistentPlayerGamemode(playerId);
}

/**
 * Cancel ball return timer for a specific ball
 * @param {string} ballId - The ball's ID
 */
export function cancelBallReturnTimer(ballId) {
    const timerId = ballReturnTimers.get(ballId);
    if (timerId) {
        system.clearRun(timerId);
        ballReturnTimers.delete(ballId);
    }
}

export const particleNames = {
    'dss_gep:dss_gep_blue_trail': '§bBlue',
    'dss_gep:dss_gep_green_trail': '§aGreen',
    'dss_gep:dss_gep_red_trail': '§cRed',
    'dss_gep:dss_gep_yellow_trail': '§eYellow',
    'dss_gep:dss_gep_gray_trail': '§8Gray'
};

/**
 * Show particle selection UI for trail effects
 * @param {Player} player - The player to show UI to
 */
function showParticleSelection(player) {
    const currentParticle = getPlayerParticlePreference(player.id);
    
    const form = new ActionFormData()
        .title("§dParticle Trail Selection")
        .body("Choose your preferred particle trail effect:")
        .button("§bBlue Trail\n§3Classic blue particle trail", 
                currentParticle === 'dss_gep:dss_gep_blue_trail' ? "textures/ui/check" : "textures/dss/gep/icons/strlb_icon.png")
        .button("§aGreen Trail\n§3Vibrant green particle trail", 
                currentParticle === 'dss_gep:dss_gep_green_trail' ? "textures/ui/check" : "textures/dss/gep/icons/strlg_icon.png")
        .button("§cRed Trail\n§3Bold red particle trail", 
                currentParticle === 'dss_gep:dss_gep_red_trail' ? "textures/ui/check" : "textures/dss/gep/icons/strlr_icon.png")
        .button("§eYellow Trail\n§3Bright yellow particle trail", 
                currentParticle === 'dss_gep:dss_gep_yellow_trail' ? "textures/ui/check" : "textures/dss/gep/icons/strly_icon.png")
        .button("§8Gray Trail\n§3Subtle gray particle trail", 
                currentParticle === 'dss_gep:dss_gep_gray_trail' ? "textures/ui/check" : "textures/dss/gep/icons/strle_icon.png");
    
    form.show(player).then(response => {
        if (response.canceled) return;
        
        const particleMap = [
            'dss_gep:dss_gep_blue_trail',
            'dss_gep:dss_gep_green_trail',
            'dss_gep:dss_gep_red_trail',
            'dss_gep:dss_gep_yellow_trail',
            'dss_gep:dss_gep_gray_trail'
        ];
        
        const selectedParticle = particleMap[response.selection];
        setPlayerParticlePreference(player.id, selectedParticle);
        
        const particleName = particleNames[selectedParticle] || '§fUnknown';
        player.onScreenDisplay.setActionBar(`§aParticle trail set to ${particleName}§a!`);
        
        // Refresh the ledger UI
        // showLedgerUI(player);
    });
}

/**
 * Get player's current particle preference
 * @param {string} playerId - The player's ID
 * @returns {string} Current particle trail identifier
 */
export function getPlayerParticlePreference(playerId) {
    return getPersistentPlayerParticlePreference(playerId);
}

/**
 * Set player's particle preference
 * @param {string} playerId - The player's ID
 * @param {string} particleId - The particle trail identifier to set
 */
export function setPlayerParticlePreference(playerId, particleId) {
    setPersistentPlayerParticlePreference(playerId, particleId);
}

/**
 * Get player's current return time preference
 * @param {string} playerId - The player's ID
 * @returns {number} Current return time in seconds (default: 5)
 */
export function getPlayerReturnTimePreference(playerId) {
    return getPersistentPlayerReturnTimePreference(playerId);
}

/**
 * Set player's return time preference
 * @param {string} playerId - The player's ID
 * @param {number} seconds - The return time in seconds to set
 */
export function setPlayerReturnTimePreference(playerId, seconds) {
    setPersistentPlayerReturnTimePreference(playerId, seconds);
}

/**
 * Toggle camera tracking preference for a player
 * @param {Player} player - The player to toggle camera tracking for
 */
function toggleCameraTracking(player) {
    const currentSetting = getPlayerCameraTrackingPreference(player.id);
    const newSetting = !currentSetting;
    
    setPlayerCameraTrackingPreference(player.id, newSetting);
    
    if (newSetting) {
        player.onScreenDisplay.setActionBar("§aBall hit camera tracking enabled!");
        player.sendMessage("§7Your camera will follow the golf ball when you hit it.");
    } else {
        player.onScreenDisplay.setActionBar("§cBall hit camera tracking disabled!");
        player.sendMessage("§7Your camera will stay in normal view when you hit the ball.");
    }
}

/**
 * Get player's camera tracking preference
 * @param {string} playerId - The player's ID
 * @returns {boolean} True if camera tracking is enabled, false otherwise
 */
export function getPlayerCameraTrackingPreference(playerId) {
    return getPersistentPlayerCameraTrackingPreference(playerId);
}

/**
 * Set player's camera tracking preference
 * @param {string} playerId - The player's ID
 * @param {boolean} enabled - Whether camera tracking should be enabled
 */
export function setPlayerCameraTrackingPreference(playerId, enabled) {
    setPersistentPlayerCameraTrackingPreference(playerId, enabled);
}

/**
 * Show return time selection UI for driving range mode
 * @param {Player} player - The player to show UI to
 */
function showReturnTimeSelection(player) {
    const currentTime = getPlayerReturnTimePreference(player.id);
    
    const form = new ActionFormData()
        .title("§9Ball Return Time")
        .body(`Current return time: §e${currentTime} seconds§r\n\nChoose how long your ball stays in driving range mode:`)
        .button("§a1 Second", "textures/dss/gep/icons/stmr1_icon.png")
        .button("§22 Seconds", "textures/dss/gep/icons/stmr2_icon.png")
        .button("§e3 Seconds", "textures/dss/gep/icons/stmr3_icon.png")
        .button("§65 Seconds", "textures/dss/gep/icons/stmr5_icon.png")
        .button("§39 Seconds", "textures/dss/gep/icons/stmr9_icon.png")
        .button("§515 Seconds", "textures/dss/gep/icons/stmr15_icon.png")
        .button("§430 Seconds", "textures/dss/gep/icons/stmr30_icon.png");
    
    form.show(player).then(response => {
        if (response.canceled) return;
        
        const timeMap = [1, 2, 3, 5, 9, 15, 30];
        
        // Predefined times only
        const selectedTime = timeMap[response.selection];
        setPlayerReturnTimePreference(player.id, selectedTime);
        player.onScreenDisplay.setActionBar(`§aBall return time set to ${selectedTime} seconds!`);
        
        // Refresh the ledger UI
        // showLedgerUI(player);
    });
}
