import WorldCollection from "../abstract/world-collection.mjs";

/** @import Scene from "../scene.mjs"; */

/**
 * The singleton collection of Scene documents which exist within the active World.
 * This Collection is accessible within the Game object as game.scenes.
 * @extends {WorldCollection<Scene>}
 * @category Collections
 *
 * @see {@link foundry.documents.Scene}: The Scene document
 * @see {@link foundry.applications.sidebar.tabs.SceneDirectory}: The SceneDirectory sidebar directory
 */
export default class Scenes extends WorldCollection {

  /* -------------------------------------------- */
  /*  Properties                                  */
  /* -------------------------------------------- */

  /** @override */
  static documentName = "Scene";

  /* -------------------------------------------- */

  /**
   * Return a reference to the Scene which is currently active
   * @type {Scene}
   */
  get active() {
    return this.find(s => s.active);
  }

  /* -------------------------------------------- */

  /**
   * Return the current Scene target.
   * This is the viewed scene if the canvas is active, otherwise it is the currently active scene.
   * @type {Scene}
   */
  get current() {
    const canvasInitialized = canvas.ready || game.settings.get("core", "noCanvas");
    return canvasInitialized ? this.viewed : this.active;
  }

  /* -------------------------------------------- */

  /**
   * Return a reference to the Scene which is currently viewed
   * @type {Scene}
   */
  get viewed() {
    return this.find(s => s.isView);
  }

  /* -------------------------------------------- */
  /*  Methods                                     */
  /* -------------------------------------------- */

  /**
   * Handle preloading the art assets for a Scene.
   * @param {string} sceneId               The Scene ID to begin loading.
   * @param {object} [options]             Additional options
   * @param {string} [options.level]       The Level ID to begin loading. Defaults to the initial level.
   * @param {boolean} [options.broadcast]  Trigger other connected clients to also preload Scene/Level resources.
   *                                       Default: `false`.
   */
  async preload(sceneId, options={}) {
    if ( typeof options === "boolean" ) {
      const msg = "You are passing the legacy \"push\" boolean to Scenes#preload. This is replaced by the"
        + " \"broadcast\" option, for example game.scenes.preload(sceneId, {broadcast: true}).";
      foundry.utils.logCompatibilityWarning(msg, {since: 14, until: 16});
      options = {broadcast: /** @type {boolean} */ options};
    }
    const {level: levelId, broadcast=false} = options;
    if ( broadcast && game.user.isGM ) game.socket.emit("preloadScene", sceneId, levelId);
    const scene = this.get(sceneId);
    if ( !scene ) return;
    const level = scene.levels.get(levelId);
    if ( levelId && !level ) return;
    const promises = [];

    // Preload sounds
    if ( scene.playlistSound?.path ) promises.push(foundry.audio.AudioHelper.preloadSound(scene.playlistSound.path));
    else if ( scene.playlist?.playbackOrder.length ) {
      const first = scene.playlist.sounds.get(scene.playlist.playbackOrder[0]);
      if ( first ) promises.push(foundry.audio.AudioHelper.preloadSound(first.path));
    }

    // Preload textures without expiring current ones
    promises.push(foundry.canvas.TextureLoader.loadSceneTextures(level ?? scene, {expireCache: false}));
    return Promise.all(promises);
  }

  /* -------------------------------------------- */
  /*  Event Handlers                              */
  /* -------------------------------------------- */

  /** @override */
  static _activateSocketListeners(socket) {
    socket.on("preloadScene", (sceneId, levelId) => this.instance.preload(sceneId, {level: levelId}));
    socket.on("pullToScene", this.#pullToScene.bind(this));
  }

  /* -------------------------------------------- */

  /**
   * Handle requests pulling the current User to a specific Scene
   * @param {string} sceneId
   * @param {object} [viewOptions]
   */
  static #pullToScene(sceneId, viewOptions) {
    const scene = game.scenes.get(sceneId);
    if ( scene ) scene.view(viewOptions);
  }

  /* -------------------------------------------- */
  /*  Importing and Exporting                     */
  /* -------------------------------------------- */

  /** @inheritDoc */
  fromCompendium(document, { clearSort=true, ...options }={}) {
    const data = super.fromCompendium(document, { clearSort, ...options });
    if ( clearSort ) {
      data.navigation = false;
      delete data.navOrder;
    }
    return data;
  }
}
