/**
 * Adapts the AVTileAdapter to manage overlays on FoundryVTT AV camera tiles.
 * Mounts/unmounts managed child elements, applies state CSS classes,
 * and observes tile re-renders so overlays survive DOM replacement.
 */
export class AVTileAdapter {
  /**
   * @param {object} adapter - Foundry adapter (injected dependency)
   */
  constructor(adapter) {
    this._adapter = adapter;
    /** @type {Map<string, MutationObserver>} */
    this._observers = new Map();
  }

  /**
   * Resolves the AV camera tile element for a given user ID.
   * @param {string} userId
   * @returns {HTMLElement|null}
   */
  _getTile(userId) {
    return (
      document.querySelector(`.camera-view[data-user-id="${userId}"]`) ??
      document.querySelector(`[data-user-id="${userId}"]`)
    );
  }

  /**
   * Mounts an overlay element onto the AV tile for the given user.
   * If an element with the same data-sp-role already exists, it is replaced.
   * The element is marked with data-sp-mount="1" for lifecycle tracking.
   * @param {string} userId
   * @param {HTMLElement} el - Must have dataset.spRole set
   */
  mount(userId, el) {
    const tile = this._getTile(userId);
    if (!tile) {
      console.warn('[ScryingPool] AVTileAdapter.mount: tile not found for', userId);
      return;
    }
    const role = el.dataset.spRole;
    if (role) {
      const existing = tile.querySelector(`[data-sp-role="${role}"]`);
      if (existing) existing.remove();
    }
    el.dataset.spMount = '1';
    tile.appendChild(el);
  }

  /**
   * Removes all managed (data-sp-mount) children from the AV tile for the given user.
   * @param {string} userId
   */
  unmount(userId) {
    const tile = this._getTile(userId);
    if (!tile) return;
    tile.querySelectorAll('[data-sp-mount]').forEach(el => el.remove());
  }

  /**
   * Sets the current state CSS class on the AV tile.
   * All previous sp-state-* classes are removed before the new one is applied.
   * Pass null to clear without adding any state class.
   * @param {string} userId
   * @param {string|null} stateName
   */
  setStateClass(userId, stateName) {
    const tile = this._getTile(userId);
    if (!tile) {
      console.warn('[ScryingPool] AVTileAdapter.setStateClass: tile not found for', userId);
      return;
    }
    const toRemove = Array.from(tile.classList).filter(c => c.startsWith('sp-state-'));
    toRemove.forEach(c => tile.classList.remove(c));
    if (stateName) {
      tile.classList.add(`sp-state-${stateName}`);
    }
  }

  /**
   * Registers a callback invoked whenever the AV tile's children change.
   * Replaces any previously registered observer for the same userId.
   * Used to re-mount overlays after Foundry re-renders the tile DOM.
   * @param {string} userId
   * @param {function(HTMLElement): void} callback
   */
  onTileRerender(userId, callback) {
    const tile = this._getTile(userId);
    if (!tile) return;

    const existing = this._observers.get(userId);
    if (existing) {
      existing.disconnect();
    }

    const observer = new MutationObserver(() => {
      callback(tile);
    });
    observer.observe(tile, { childList: true });
    this._observers.set(userId, observer);
  }

  /**
   * Disconnects all active MutationObservers and clears the observer map.
   * Safe to call multiple times.
   */
  disconnect() {
    this._observers.forEach(obs => obs.disconnect());
    this._observers.clear();
  }
}
