// Golf System Persistence Manager
// Handles migration from Map-based storage to world dynamic properties for persistent data

import { world } from "@minecraft/server";

/**
 * Default player data structure
 */
const DEFAULT_PLAYER_DATA = {
    swingCount: 0,
    currentRound: {
        holes: [],
        startTime: Date.now()
    },
    activeBallId: null,
    gamemode: 'golf_course',
    preferences: {
        particles: 'dss_gep:dss_gep_blue_trail',
        returnTime: 5,
        cameraTracking: true,
        clubOptions: {}
    }
};

/**
 * Get player's persistent golf data from world dynamic properties
 * @param {string} playerId - The player's ID
 * @returns {Object} Player's golf data
 */
export function getPlayerGolfData(playerId) {
    const dataKey = `golf_player_${playerId}`;
    const savedData = world.getDynamicProperty(dataKey);
    
    if (!savedData) {
        // Return default data for new players
        return JSON.parse(JSON.stringify(DEFAULT_PLAYER_DATA));
    }
    
    try {
        const playerData = JSON.parse(savedData);
        // Merge with defaults to handle missing properties from older versions
        return {
            ...DEFAULT_PLAYER_DATA,
            ...playerData,
            preferences: {
                ...DEFAULT_PLAYER_DATA.preferences,
                ...playerData.preferences
            }
        };
    } catch (error) {
        // console.warn(`Failed to parse golf data for player ${playerId}:`, error);
        return JSON.parse(JSON.stringify(DEFAULT_PLAYER_DATA));
    }
}

/**
 * Save player's persistent golf data to world dynamic properties
 * @param {string} playerId - The player's ID
 * @param {Object} playerData - The player's golf data to save
 */
export function savePlayerGolfData(playerId, playerData) {
    const dataKey = `golf_player_${playerId}`;
    
    try {
        // Ensure we have a valid structure
        const dataToSave = {
            ...DEFAULT_PLAYER_DATA,
            ...playerData,
            preferences: {
                ...DEFAULT_PLAYER_DATA.preferences,
                ...playerData.preferences
            }
        };
        
        world.setDynamicProperty(dataKey, JSON.stringify(dataToSave));
    } catch (error) {
        // console.warn(`Failed to save golf data for player ${playerId}:`, error);
    }
}

/**
 * Update a specific field in player's golf data
 * @param {string} playerId - The player's ID
 * @param {string} field - The field to update (dot notation supported)
 * @param {*} value - The new value
 */
export function updatePlayerGolfData(playerId, field, value) {
    const playerData = getPlayerGolfData(playerId);
    
    // Handle dot notation for nested fields
    const fieldParts = field.split('.');
    let current = playerData;
    
    // Navigate to the parent of the field to update
    for (let i = 0; i < fieldParts.length - 1; i++) {
        if (!current[fieldParts[i]]) {
            current[fieldParts[i]] = {};
        }
        current = current[fieldParts[i]];
    }
    
    // Set the final value
    current[fieldParts[fieldParts.length - 1]] = value;
    
    savePlayerGolfData(playerId, playerData);
}

/**
 * Get player's current swing count
 * @param {string} playerId - The player's ID
 * @returns {number} Current swing count
 */
export function getPlayerSwingCount(playerId) {
    const playerData = getPlayerGolfData(playerId);
    return playerData.swingCount || 0;
}

/**
 * Set player's current swing count
 * @param {string} playerId - The player's ID
 * @param {number} count - The swing count to set
 */
export function setPlayerSwingCount(playerId, count) {
    updatePlayerGolfData(playerId, 'swingCount', count);
}

/**
 * Increment player's swing count
 * @param {string} playerId - The player's ID
 * @returns {number} New swing count
 */
export function incrementPlayerSwingCount(playerId) {
    const currentCount = getPlayerSwingCount(playerId);
    const newCount = currentCount + 1;
    setPlayerSwingCount(playerId, newCount);
    return newCount;
}

/**
 * Reset player's swing count
 * @param {string} playerId - The player's ID
 */
export function resetPlayerSwingCount(playerId) {
    setPlayerSwingCount(playerId, 0);
}

/**
 * Get player's current round data
 * @param {string} playerId - The player's ID
 * @returns {Object} Current round data
 */
export function getPlayerCurrentRound(playerId) {
    const playerData = getPlayerGolfData(playerId);
    return playerData.currentRound || {
        holes: [],
        startTime: Date.now()
    };
}

/**
 * Set player's current round data
 * @param {string} playerId - The player's ID
 * @param {Object} roundData - The round data to set
 */
export function setPlayerCurrentRound(playerId, roundData) {
    updatePlayerGolfData(playerId, 'currentRound', roundData);
}

/**
 * Add a hole to player's current round
 * @param {string} playerId - The player's ID
 * @param {Object} holeData - The hole data to add
 */
export function addHoleToCurrentRound(playerId, holeData) {
    const roundData = getPlayerCurrentRound(playerId);
    roundData.holes.push(holeData);
    setPlayerCurrentRound(playerId, roundData);
}

/**
 * Clear player's current round (start fresh)
 * @param {string} playerId - The player's ID
 */
export function clearPlayerCurrentRound(playerId) {
    setPlayerCurrentRound(playerId, {
        holes: [],
        startTime: Date.now()
    });
}

/**
 * Get player's active ball ID
 * @param {string} playerId - The player's ID
 * @returns {string|null} Active ball ID or null
 */
export function getPlayerActiveBallId(playerId) {
    const playerData = getPlayerGolfData(playerId);
    return playerData.activeBallId || null;
}

/**
 * Set player's active ball ID
 * @param {string} playerId - The player's ID
 * @param {string|null} ballId - The ball ID to set (or null to clear)
 */
export function setPlayerActiveBallId(playerId, ballId) {
    updatePlayerGolfData(playerId, 'activeBallId', ballId);
}

/**
 * Get player's gamemode preference
 * @param {string} playerId - The player's ID
 * @returns {string} Gamemode ('golf_course' or 'driving_range')
 */
export function getPlayerGamemode(playerId) {
    const playerData = getPlayerGolfData(playerId);
    return playerData.gamemode || 'golf_course';
}

/**
 * Set player's gamemode preference
 * @param {string} playerId - The player's ID
 * @param {string} gamemode - The gamemode to set
 */
export function setPlayerGamemode(playerId, gamemode) {
    updatePlayerGolfData(playerId, 'gamemode', gamemode);
}

/**
 * Get player's particle preference
 * @param {string} playerId - The player's ID
 * @returns {string} Particle trail identifier
 */
export function getPlayerParticlePreference(playerId) {
    const playerData = getPlayerGolfData(playerId);
    return playerData.preferences.particles || 'dss_gep:dss_gep_blue_trail';
}

/**
 * Set player's particle preference
 * @param {string} playerId - The player's ID
 * @param {string} particleId - The particle trail identifier
 */
export function setPlayerParticlePreference(playerId, particleId) {
    updatePlayerGolfData(playerId, 'preferences.particles', particleId);
}

/**
 * Get player's return time preference
 * @param {string} playerId - The player's ID
 * @returns {number} Return time in seconds
 */
export function getPlayerReturnTimePreference(playerId) {
    const playerData = getPlayerGolfData(playerId);
    return playerData.preferences.returnTime || 5;
}

/**
 * Set player's return time preference
 * @param {string} playerId - The player's ID
 * @param {number} seconds - The return time in seconds
 */
export function setPlayerReturnTimePreference(playerId, seconds) {
    const clampedSeconds = Math.max(1, Math.min(30, seconds));
    updatePlayerGolfData(playerId, 'preferences.returnTime', clampedSeconds);
}

/**
 * Get player's camera tracking preference
 * @param {string} playerId - The player's ID
 * @returns {boolean} True if camera tracking is enabled
 */
export function getPlayerCameraTrackingPreference(playerId) {
    const playerData = getPlayerGolfData(playerId);
    return playerData.preferences.cameraTracking !== false; // Default to true
}

/**
 * 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) {
    updatePlayerGolfData(playerId, 'preferences.cameraTracking', enabled);
}

/**
 * Get player's club options for a specific club type
 * @param {string} playerId - The player's ID
 * @param {string} clubType - The club type ID
 * @returns {Object|null} Club options or null if not set
 */
export function getPlayerClubOptions(playerId, clubType) {
    const playerData = getPlayerGolfData(playerId);
    return playerData.preferences.clubOptions[clubType] || null;
}

/**
 * Set player's club options for a specific club type
 * @param {string} playerId - The player's ID
 * @param {string} clubType - The club type ID
 * @param {Object} options - Club options {strength, arcAngle}
 */
export function setPlayerClubOptions(playerId, clubType, options) {
    const playerData = getPlayerGolfData(playerId);
    if (!playerData.preferences.clubOptions) {
        playerData.preferences.clubOptions = {};
    }
    playerData.preferences.clubOptions[clubType] = options;
    savePlayerGolfData(playerId, playerData);
}

/**
 * Clear all club options for a player
 * @param {string} playerId - The player's ID
 */
export function clearPlayerClubOptions(playerId) {
    updatePlayerGolfData(playerId, 'preferences.clubOptions', {});
}

/**
 * Clear all golf data for a player (complete reset)
 * @param {string} playerId - The player's ID
 */
export function clearAllPlayerGolfData(playerId) {
    const dataKey = `golf_player_${playerId}`;
    const roundsKey = `golf_rounds_${playerId}`;
    
    // Clear current session data
    world.setDynamicProperty(dataKey, JSON.stringify(DEFAULT_PLAYER_DATA));
    
    // Clear completed rounds history
    world.setDynamicProperty(roundsKey, "[]");
}

/**
 * Migrate existing Map-based data to world dynamic properties
 * This function should be called once during the transition period
 * @param {Map} playerSwingCount - Current swing count map
 * @param {Map} currentRoundData - Current round data map
 * @param {Map} playerGamemodes - Player gamemode map
 * @param {Map} playerParticlePreferences - Particle preferences map
 * @param {Map} playerReturnTimePreferences - Return time preferences map
 * @param {Map} playerCameraTrackingPreferences - Camera tracking preferences map
 * @param {Map} playerClubOptions - Club options map
 * @param {Map} playerActiveBalls - Active balls map
 */
export function migrateMapDataToWorldProperties(
    playerSwingCount,
    currentRoundData,
    playerGamemodes,
    playerParticlePreferences,
    playerReturnTimePreferences,
    playerCameraTrackingPreferences,
    playerClubOptions,
    playerActiveBalls
) {
    // console.log("Starting migration from Maps to world dynamic properties...");
    
    // Get all unique player IDs from all maps
    const allPlayerIds = new Set();
    
    [playerSwingCount, currentRoundData, playerGamemodes, playerParticlePreferences,
     playerReturnTimePreferences, playerCameraTrackingPreferences, playerClubOptions, playerActiveBalls]
        .forEach(map => {
            if (map && map.keys) {
                for (const playerId of map.keys()) {
                    allPlayerIds.add(playerId);
                }
            }
        });
    
    let migratedCount = 0;
    
    // Migrate data for each player
    for (const playerId of allPlayerIds) {
        try {
            const playerData = getPlayerGolfData(playerId); // Get existing or default data
            
            // Migrate swing count
            if (playerSwingCount && playerSwingCount.has(playerId)) {
                playerData.swingCount = playerSwingCount.get(playerId);
            }
            
            // Migrate current round data
            if (currentRoundData && currentRoundData.has(playerId)) {
                playerData.currentRound = currentRoundData.get(playerId);
            }
            
            // Migrate active ball ID
            if (playerActiveBalls && playerActiveBalls.has(playerId)) {
                playerData.activeBallId = playerActiveBalls.get(playerId);
            }
            
            // Migrate gamemode
            if (playerGamemodes && playerGamemodes.has(playerId)) {
                playerData.gamemode = playerGamemodes.get(playerId);
            }
            
            // Migrate preferences
            if (playerParticlePreferences && playerParticlePreferences.has(playerId)) {
                playerData.preferences.particles = playerParticlePreferences.get(playerId);
            }
            
            if (playerReturnTimePreferences && playerReturnTimePreferences.has(playerId)) {
                playerData.preferences.returnTime = playerReturnTimePreferences.get(playerId);
            }
            
            if (playerCameraTrackingPreferences && playerCameraTrackingPreferences.has(playerId)) {
                playerData.preferences.cameraTracking = playerCameraTrackingPreferences.get(playerId);
            }
            
            if (playerClubOptions && playerClubOptions.has(playerId)) {
                playerData.preferences.clubOptions = playerClubOptions.get(playerId) || {};
            }
            
            // Save migrated data
            savePlayerGolfData(playerId, playerData);
            migratedCount++;
            
        } catch (error) {
            // console.warn(`Failed to migrate data for player ${playerId}:`, error);
        }
    }
    
    // console.log(`Migration completed. Migrated data for ${migratedCount} players.`);
    return migratedCount;
}
