// @ts-nocheck

// Conditional base class — test environment lacks foundry globals.
// At module load time in tests, foundry is undefined → fallback class is used.

/** @private */
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() {}
      };

/**
 * Dialog for loading a scene preset.
 * Extends ApplicationV2 via HandlebarsApplicationMixin.
 */
export class PresetLoadDialog extends _AppBase {
  static DEFAULT_OPTIONS = {
    id: 'scrying-pool-preset-load-dialog',
    classes: ['scrying-pool', 'preset-load-dialog'],
    window: { title: 'Load Scene Preset', resizable: false },
    position: { width: 320, height: 'auto' },
  };

  static PARTS = {
    dialog: {
      template: 'modules/scrying-pool/templates/preset-load-dialog.hbs',
    },
  };

  /**
   * @param {import('../../core/ScenePresetManager.js').ScenePresetManager} scenePresetManager
   *   Injected ScenePresetManager for preset operations.
   * @param {import('../../foundry/FoundryAdapter.js').FoundryAdapter} adapter
   *   Injected FoundryAdapter surface.
   * @param {object} [options]
   */
  constructor(scenePresetManager, adapter, options = {}) {
    // Validate dependencies
    if (!scenePresetManager || typeof scenePresetManager !== 'object') {
      throw new TypeError('PresetLoadDialog: scenePresetManager argument is required and must be an object');
    }
    if (!adapter || typeof adapter !== 'object') {
      throw new TypeError('PresetLoadDialog: adapter argument is required and must be an object');
    }

    super(options);
    this._scenePresetManager = scenePresetManager;
    this._adapter = adapter;
    /** @type {Array<import('../../contracts/scene-preset.js').ScenePreset>} */
    this._presets = [];
  }

  /**
   * Prepares the template context with i18n labels and preset list.
   * @returns {Promise<object>} Template context.
   */
  async _prepareContext() {
    const i18n = this._adapter.i18n;

    // Get list of presets from manager
    this._presets = this._scenePresetManager.list();

    return {
      presets: this._presets,
      hasPresets: this._presets.length > 0,
      loadLabel: i18n.localize('scrying-pool.presets.load.loadButton'),
      cancelLabel: i18n.localize('scrying-pool.presets.load.cancelButton'),
      title: i18n.localize('scrying-pool.presets.load.title'),
      emptyMessage: i18n.localize('scrying-pool.presets.load.emptyMessage'),
    };
  }

  /**
   * Sets up event handlers after rendering.
   * @param {HTMLElement|JQuery|object} html - The dialog element, jQuery object, or plain object with querySelector.
   */
  _onRender(html) {
    // Normalize html to element with querySelector
    // FoundryVTT ApplicationV2 passes jQuery object, tests pass plain objects
    const element = html instanceof HTMLElement 
      ? html 
      : (html?.[0] ?? html);
    if (!element || typeof element.querySelector !== 'function') return;

    // Set up load button handlers for each preset
    const loadButtons = element.querySelectorAll('[data-action="load"]');
    loadButtons.forEach((btn) => {
      btn.addEventListener('click', () => {
        const presetName = btn.dataset.presetName;
        if (presetName) {
          this._onLoad(presetName);
        }
      });
    });

    // Cancel button handler
    const cancelBtn = element.querySelector('[data-action="cancel"]');
    if (cancelBtn) {
      cancelBtn.addEventListener('click', () => this._onCancel());
    }

    // Keyboard support
    element.addEventListener('keydown', (event) => this._onKeydown(event));
  }

  /**
   * Handles keyboard events for dialog navigation.
   * @param {KeyboardEvent} event - The keyboard event.
   */
  _onKeydown(event) {
    // Escape key cancels the dialog
    if (event.key === 'Escape') {
      event.preventDefault();
      event.stopPropagation();
      this._onCancel();
    }
    // Enter key on a load button triggers load
    else if (event.key === 'Enter' && event.target.dataset?.action === 'load') {
      event.preventDefault();
      event.stopPropagation();
      const presetName = event.target.dataset.presetName;
      if (presetName) {
        this._onLoad(presetName);
      }
    }
  }

  /**
   * Handles loading a preset by name.
   * @param {string} presetName - The preset name to load.
   * @throws {TypeError} If preset name is invalid.
   */
  async _onLoad(presetName) {
    if (typeof presetName !== 'string' || presetName.length === 0) {
      throw new TypeError('PresetLoadDialog._onLoad: presetName must be a non-empty string');
    }

    try {
      await this._scenePresetManager.load(presetName);

      // Show success notification
      this._adapter.notifications.info(
        this._adapter.i18n.localize('scrying-pool.presets.notifications.applied')
          .replace('{name}', presetName)
      );

      // Close dialog
      await this.close();
    } catch (err) {
      // Re-throw validation errors from ScenePresetManager
      if (err instanceof TypeError) {
        throw err;
      }
      // For other errors, log and re-throw
      console.error('[ScryingPool] PresetLoadDialog: failed to load preset:', err);
      throw err;
    }
  }

  /**
   * Handles cancel action — closes the dialog.
   */
  _onCancel() {
    this.close();
  }
}
