/**
 * GMActorMappingPanel — GM settings submenu for assigning actors to users
 * for the Token Video Overlay feature.
 *
 * The GM maps an actor to a user's webcam feed. When "Show Webcam Video on
 * Tokens" is enabled, any token of the mapped actor will display that user's
 * webcam instead of the token icon.
 *
 * Extends ApplicationV2 via HandlebarsApplicationMixin.
 * Uses module-level _adapter for DI (same pattern as PlayerPrivacyPanelMenu).
 *
 * @module ui/gm/GMActorMappingPanel
 */

/** @type {import('../../foundry/FoundryAdapter.js').FoundryAdapter|null} */
let _adapter = null;

/**
 * Initialize static adapter reference. Called once from module.js ready hook.
 * @param {import('../../foundry/FoundryAdapter.js').FoundryAdapter} adapter
 */
export function initGMActorMappingPanel(adapter) {
  _adapter = adapter;
}

const _AppBase =
  typeof foundry !== 'undefined' &&
  foundry.applications?.api?.HandlebarsApplicationMixin &&
  foundry.applications?.api?.ApplicationV2
    ? foundry.applications.api.HandlebarsApplicationMixin(
        foundry.applications.api.ApplicationV2
      )
    : class _FallbackApp {
        static DEFAULT_OPTIONS = {};
        static PARTS = {};
        get rendered() { return this._rendered ?? false; }
        set rendered(v) { this._rendered = v; }
        get element() { return this._element ?? null; }
        set element(v) { this._element = v; }
        async render() { this._rendered = true; }
        async close() { this._rendered = false; }
        async _prepareContext() { return {}; }
        _onRender() {}
        _onClose() {}
        _onPosition() {}
      };

/**
 * GM Actor Mapping Panel — assign actors to user webcams for token overlay.
 */
export class GMActorMappingPanel extends _AppBase {
  static DEFAULT_OPTIONS = {
    id: 'scrying-pool-actor-mapping',
    classes: ['scrying-pool', 'actor-mapping'],
    window: {
      title: 'SCRYING_POOL.ActorMapping.title',
      resizable: false,
      width: 450,
      height: 'auto',
    },
    position: {},
  };

  static PARTS = {
    form: {
      template: 'modules/scrying-pool/templates/actor-mapping.hbs',
    },
  };

  async _prepareContext() {
    const mapping = _adapter?.settings?.get('userActorMapping') ?? {};
    const selectedId = (uid) => mapping[uid] ?? '';

    const sortedActors = _adapter.actors.all()
      .map(a => ({ id: a.id, name: a.name }))
      .sort((a, b) => a.name.localeCompare(b.name));

    const users = _adapter.users.all()
      .map(u => ({
        id: u.id,
        name: u.name,
        isGM: u.isGM,
        avatar: u.avatar ?? 'icons/svg/mystery-man.svg',
        actors: sortedActors.map(a => ({
          id: a.id,
          name: a.name,
          selected: a.id === selectedId(u.id),
        })),
      }))
      .sort((a, b) => {
        if (a.isGM && !b.isGM) return -1;
        if (!a.isGM && b.isGM) return 1;
        return a.name.localeCompare(b.name);
      });

    return {
      hasNoUsers: users.length === 0,
      users,
    };
  }

  _onRender(context, options) {
    if (this._formHandlerAttached) return;
    this._formHandlerAttached = true;

    const form = this.element?.querySelector('form');
    if (!form) return;

    form.addEventListener('change', (event) => {
      const select = event.target;
      if (select.tagName !== 'SELECT') return;

      const mapping = { ...(_adapter?.settings?.get('userActorMapping') ?? {}) };
      if (select.value) {
        mapping[select.name] = select.value;
      } else {
        delete mapping[select.name];
      }
      _adapter?.settings?.set('userActorMapping', mapping).catch(err => {
        console.error('[ScryingPool] Failed to save actor mapping:', err);
      });
    });
  }
}
