// modules/dss_sound_proximity.js

import { world, system } from "@minecraft/server";
import { CONFIG } from '../dss_sound_config.js';
import { 
  log, 
  calculateDistance, 
  canPlaySound, 
  playSound, 
  stopSound, 
  getEnabledSoundsByEvent 
} from './dss_sound_helper.js';

/**
 * Registers all proximity-based sounds defined in the configuration.
 */
export function registerProximitySounds() {
  const proximitySounds = getEnabledSoundsByEvent("proximity");

  proximitySounds.forEach(proximityConfig => {
    handleProximity(proximityConfig);
    log(`Registered proximity sound "${proximityConfig.SOUND}" for entity "${proximityConfig.ENTITY}".`, 'PROXIMITY');
  });
}

/**
 * Handles a single proximity-based sound configuration.
 * Sets up listeners and schedulers for the proximity sound.
 * @param {Object} proximityConfig - The proximity sound configuration.
 */
function handleProximity(proximityConfig) {
  const {
    ENTITY,
    SOUND,
    BASE_VOLUME,
    BASE_PITCH,
    UPDATE_INTERVAL,
    MIN_DELAY,
    MAX_SOUND_DISTANCE,
    DEBUG
  } = proximityConfig;

  /**
   * Tracks active proximity sounds for each player for this specific proximity configuration.
   * @type {Set<string>} - Set of player names who currently have the proximity sound active.
   */
  const activePlayers = new Set();

  /**
   * Updates the proximity sound for a single player based on nearby entities.
   * @param {import("@minecraft/server").Player} player 
   */
  const updateProximityForPlayer = (player) => {
    try {
      if (CONFIG.DEBUG.PROXIMITY || CONFIG.DEBUG.ALL || DEBUG) {
        log(`[DEBUG] Updating proximity for player: ${player.name}`, 'PROXIMITY');
      }

      // Fetch nearby entities of the specified type
      const nearbyEntities = world.getEntities({
        location: player.location,
        maxDistance: MAX_SOUND_DISTANCE,
        type: ENTITY
      });

      if (CONFIG.DEBUG.PROXIMITY || CONFIG.DEBUG.ALL || DEBUG) {
        log(`[DEBUG] Found ${nearbyEntities.length} ${ENTITY}s near player: ${player.name}`, 'PROXIMITY');
      }

      if (nearbyEntities.length === 0) {
        // No relevant entities nearby; stop any active proximity sounds
        if (activePlayers.has(player.name)) {
          try {
            stopSound(player, SOUND);
            activePlayers.delete(player.name);
            log(`Stopped proximity sound "${SOUND}" for player: ${player.name}`, 'PROXIMITY');
          } catch (error) {
            log(`Error stopping sound "${SOUND}" for player "${player.name}": ${error.message}`, 'PROXIMITY');
          }
        }
        return;
      }

      // Find the closest relevant entity
      let closestDistance = Infinity;
      nearbyEntities.forEach(entity => {
        const distance = calculateDistance(player.location, entity.location);
        if (distance < closestDistance) {
          closestDistance = distance;
        }
      });

      // Calculate sound properties based on distance
      const normalizedDistance = Math.min(closestDistance / MAX_SOUND_DISTANCE, 1);
      const volume = BASE_VOLUME * (1 - normalizedDistance ** 2); // Volume attenuation
      const pitch = BASE_PITCH * (1 - normalizedDistance / 2); // Pitch attenuation

      if (CONFIG.DEBUG.PROXIMITY || CONFIG.DEBUG.ALL || DEBUG) {
        log(`[DEBUG] Closest distance: ${closestDistance.toFixed(2)}, Volume: ${volume.toFixed(2)}, Pitch: ${pitch.toFixed(2)}`, 'PROXIMITY');
      }

      if (!activePlayers.has(player.name)) {
        // Play the proximity sound
        playSound(player, SOUND, { volume, pitch, loop: true });
        activePlayers.add(player.name);
        log(`Played proximity sound "${SOUND}" for player: ${player.name} with volume: ${volume.toFixed(2)} and pitch: ${pitch.toFixed(2)}`, 'PROXIMITY');

        // Schedule the next update based on MIN_DELAY (ticks)
        system.runTimeout(() => {
          activePlayers.delete(player.name);
          updateProximityForPlayer(player);
        }, MIN_DELAY); // MIN_DELAY is already in ticks
      }
      // If the sound is already active, dynamic updates aren't handled in this implementation
    } catch (error) {
      if (CONFIG.DEBUG.PROXIMITY || CONFIG.DEBUG.ALL || DEBUG) {
        console.error(`[ERROR] handleProximity for "${SOUND}": ${error.message}`);
      }
    }
  };

  /**
   * Sets up proximity checks for all current and future players.
   */
  const setupProximity = () => {
    // Handle new players spawning in the world
    world.afterEvents.playerSpawn.subscribe(event => {
      const player = event.player;
      log(`Player spawned: ${player.name}. Starting proximity checks for sound: "${SOUND}"`, 'PROXIMITY');

      // Add a delay before starting proximity checks
      system.runTimeout(() => {
        system.runInterval(() => {
          updateProximityForPlayer(player);
        }, UPDATE_INTERVAL); // UPDATE_INTERVAL is in ticks
      }, 60); // Delay in ticks (3 seconds)
    });

    // Handle existing players when the script loads
    world.getPlayers().forEach(player => {
      log(`Initializing proximity checks for existing player: ${player.name} and sound: "${SOUND}"`, 'PROXIMITY');

      // Add a delay before starting proximity checks
      system.runTimeout(() => {
        system.runInterval(() => {
          updateProximityForPlayer(player);
        }, UPDATE_INTERVAL); // UPDATE_INTERVAL is in ticks
      }, 60); // Delay in ticks (3 seconds)
    });
  };

  // Initialize proximity handling
  setupProximity();
}

// Add batching for proximity checks
function batchProximityChecks(players, entities, config) {
  const results = new Map();
  
  // Pre-calculate entity positions once
  const entityPositions = entities.map(e => ({
    entity: e,
    pos: e.location
  }));

  // Batch process all players
  for (const player of players) {
    const playerPos = player.location;
    const nearbyEntities = entityPositions.filter(e => 
      calculateDistance(playerPos, e.pos) <= config.MAX_SOUND_DISTANCE
    );
    results.set(player, nearbyEntities);
  }
  
  return results;
}
