// @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 saving a scene preset.
 * Extends ApplicationV2 via HandlebarsApplicationMixin.
 */
export class PresetSaveDialog extends _AppBase {
  static DEFAULT_OPTIONS = {
    id: 'scrying-pool-preset-save-dialog',
    classes: ['scrying-pool', 'preset-save-dialog'],
    window: { title: 'Save Scene Preset', resizable: false },
    position: { width: 360, height: 'auto' },
  };

  static PARTS = {
    dialog: {
      template: 'modules/scrying-pool/templates/preset-save-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('PresetSaveDialog: scenePresetManager argument is required and must be an object');
    }
    if (!adapter || typeof adapter !== 'object') {
      throw new TypeError('PresetSaveDialog: adapter argument is required and must be an object');
    }

    super(options);
    this._scenePresetManager = scenePresetManager;
    this._adapter = adapter;
    /** @type {HTMLElement|null} */
    this._nameInput = null;
  }

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

    return {
      defaultName: '',
      saveLabel: i18n.localize('scrying-pool.presets.save.saveButton'),
      cancelLabel: i18n.localize('scrying-pool.presets.save.cancelButton'),
      title: i18n.localize('scrying-pool.presets.save.title'),
      nameLabel: i18n.localize('scrying-pool.presets.save.nameLabel'),
      namePlaceholder: i18n.localize('scrying-pool.presets.save.namePlaceholder'),
      descriptionHint: i18n.localize('scrying-pool.presets.save.descriptionHint'),
    };
  }

  /**
   * 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;

    // Cache the name input
    this._nameInput = element.querySelector('[name="presetName"]');

    // Focus the name input
    if (this._nameInput) {
      this._nameInput.focus();
    }

    // Form submit handler
    const form = element.querySelector('form');
    if (form) {
      form.addEventListener('submit', (event) => this._onSubmit(event));
    }

    // 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) {
    // Enter key on input field triggers save
    if (event.key === 'Enter' && event.target.tagName === 'INPUT') {
      event.preventDefault();
      event.stopPropagation();
      const submitEvent = { preventDefault: () => {}, stopPropagation: () => {}, target: event.target.form };
      this._onSubmit(submitEvent);
    }
    // Escape key cancels the dialog
    else if (event.key === 'Escape') {
      event.preventDefault();
      event.stopPropagation();
      this._onCancel();
    }
  }

  /**
   * Handles form submission to save a preset.
   * @param {Event} event - The form submit event.
   * @throws {TypeError} If name is invalid.
   */
  async _onSubmit(event) {
    if (!event) {
      throw new TypeError('PresetSaveDialog._onSubmit: event is required');
    }

    event.preventDefault();
    event.stopPropagation();

    // Get preset name from form
    const form = event.target;
    const nameInput = form.querySelector('[name="presetName"]');
    if (!nameInput) {
      throw new TypeError('PresetSaveDialog._onSubmit: preset name input not found');
    }

    const name = nameInput.value?.trim();

    // Validate name
    if (typeof name !== 'string' || name.length === 0) {
      throw new TypeError('PresetSaveDialog._onSubmit: preset name must be a non-empty string');
    }

    // Save preset via manager
    try {
      await this._scenePresetManager.save(name);

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

      // 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] PresetSaveDialog: failed to save preset:', err);
      throw err;
    }
  }

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