// modules/dss_sound_effects.js

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

// Import the Proximity Sound Module
import { registerProximitySounds } from './dss_sound_proximity.js';
import { registerTagSoundSystem } from "./dss_sound_tagging.js";

/**
 * Handles block interaction events.
 * @param {PlayerInteractWithBlockAfterEvent} event - The block interaction event.
 * @param {Object} config - The sound configuration.
 */
function handleBlockInteract(event, config) {
  const { BLOCK, SOUND, VOLUME, PITCH, LOOPED, CONDITIONS, WITH_ITEM } = config;

  if (event.block.typeId !== BLOCK) {
    return;
  }

  if (WITH_ITEM && !event.itemStack) {
    log(`Block interaction requires an item, but none was used.`, 'SOUND_EFFECT');
    return;
  }

  if (!checkConditions(CONDITIONS, event)) {
    log(`Event conditions not met for sound: ${SOUND}`, 'SOUND_EFFECT');
    return;
  }

  // Implement cooldown to prevent spamming
  if (!canPlaySound(event.player.name, SOUND, 1000)) { // 1 second cooldown
    return;
  }

  playSound(event.player, SOUND, { VOLUME, PITCH, loop: LOOPED });
}

/**
 * Handles entity hurt events.
 * @param {EntityHurtEvent} event - The entity hurt event.
 * @param {Object} config - The sound configuration.
 */
function handleEntityHurt(event, config) {
  const { ENTITY, SOUND, VOLUME, PITCH, LOOPED, CONDITIONS } = config;

  const damagingEntity = event.damageSource.damagingEntity;
  if (!damagingEntity) {
    return;
  }

  if (!checkConditions(CONDITIONS, event)) {
    log(`Event conditions not met for sound: ${SOUND}`, 'SOUND_EFFECT');
    return;
  }

  if (damagingEntity) { // Ensure it's a player entity
    // Implement cooldown
    if (!canPlaySound(damagingEntity.name, SOUND, 1000)) {
      return;
    }
    playSound(damagingEntity, SOUND, { VOLUME, PITCH, loop: LOOPED });
  }
}

/**
 * Handles item use events.
 * @param {PlayerUseItemAfterEvent} event - The item use event.
 * @param {Object} config - The sound configuration.
 */
function handleItemUse(event, config) {
  const { ITEM, SOUND, VOLUME, PITCH, LOOPED, CONDITIONS } = config;

  if (event.itemStack?.typeId !== ITEM) {
    return;
  }

  if (!checkConditions(CONDITIONS, event)) {
    log(`Event conditions not met for sound: ${SOUND}`, 'SOUND_EFFECT');
    return;
  }

  // Implement cooldown
  if (!canPlaySound(event.source.name, SOUND, 1000)) {
    return;
  }

  playSound(event.source, SOUND, { VOLUME, PITCH, loop: LOOPED });
}

/**
 * Handles player spawn events (used for background music).
 * @param {PlayerSpawnEvent} event - The player spawn event.
 * @param {Object} config - The sound configuration.
 */
function handlePlayerSpawn(event, config) {
  const { SOUND, VOLUME, PITCH, LOOPED, CONDITIONS } = config;

  if (!checkConditions(CONDITIONS, event)) {
    log(`Event conditions not met for sound: ${SOUND}`, 'SOUND_EFFECT');
    return;
  }

  // Determine the sound to play (supporting multiple background tracks)
  const selectedSound = Array.isArray(SOUND) ? SOUND[Math.floor(Math.random() * SOUND.length)] : SOUND;

  // Implement cooldown
  if (!canPlaySound(event.player.name, selectedSound, 1000)) {
    return;
  }

  system.runTimeout(() => {
    playSound(event.player, selectedSound, { VOLUME, PITCH, loop: LOOPED });
  }, 60); // Delay in ticks (3 seconds if 20 ticks per second)
}

// Add a priority queue for sounds
class SoundPriorityQueue {
  constructor() {
    this.queue = new Map(); // player -> PriorityQueue<Sound>
  }

  addSound(player, sound, priority) {
    if (!this.queue.has(player)) {
      this.queue.set(player, []);
    }
    const playerQueue = this.queue.get(player);
    const soundEntry = { sound, priority, timestamp: Date.now() };
    
    // Insert maintaining priority order
    const insertIndex = playerQueue.findIndex(entry => entry.priority > priority);
    if (insertIndex === -1) {
      playerQueue.push(soundEntry);
    } else {
      playerQueue.splice(insertIndex, 0, soundEntry);
    }
  }

  getNextSound(player) {
    return this.queue.get(player)?.shift();
  }
}

/**
 * Registers event listeners based on the sound configurations.
 */
export function registerSoundEffects() {
  const sounds = getEnabledSounds();

  // Aggregate sounds by event type to minimize event subscriptions
  const eventMap = sounds.reduce((map, soundEntry) => {
    const { config } = soundEntry;
    if (!map[config.EVENT]) {
      map[config.EVENT] = [];
    }
    map[config.EVENT].push(soundEntry.config);
    return map;
  }, {});

  // Register blockInteract event listener
  if (eventMap.blockInteract) {
    world.afterEvents.playerInteractWithBlock.subscribe(event => {
      eventMap.blockInteract.forEach(config => handleBlockInteract(event, config));
    });
    log(`Registered blockInteract listeners for ${eventMap.blockInteract.length} sounds.`, 'SOUND_EFFECT');
  }

  // Register entityHurt event listener
  if (eventMap.entityHurt) {
    world.afterEvents.entityHurt.subscribe(event => {
      eventMap.entityHurt.forEach(config => handleEntityHurt(event, config));
    });
    log(`Registered entityHurt listeners for ${eventMap.entityHurt.length} sounds.`, 'SOUND_EFFECT');
  }

  // Register itemUse event listener
  if (eventMap.itemUse) {
    world.afterEvents.itemUse.subscribe(event => {
      eventMap.itemUse.forEach(config => handleItemUse(event, config));
    });
    log(`Registered itemUse listeners for ${eventMap.itemUse.length} sounds.`, 'SOUND_EFFECT');
  }

  // Register playerSpawn event listener (for background music)
  if (eventMap.playerSpawn) {
    world.afterEvents.playerSpawn.subscribe(event => {
      eventMap.playerSpawn.forEach(config => handlePlayerSpawn(event, config));
    });
    log(`Registered playerSpawn listeners for ${eventMap.playerSpawn.length} sounds.`, 'SOUND_EFFECT');
  }

  // Register proximity-based sound handlers
  if (eventMap.proximity) {
    registerProximitySounds();
    log(`Registered proximity listeners for ${eventMap.proximity.length} sounds.`, 'PROXIMITY');
  }
}
