import { TVA_CONFIG, updateSettings } from '../scripts/settings.js';
import { showPathSelectCategoryDialog, showPathSelectConfigForm } from './dialogs.js';

export class ForgeSearchPaths extends FormApplication {
  constructor() {
    super({}, {});
  }

  static get defaultOptions() {
    return mergeObject(super.defaultOptions, {
      id: 'token-variants-search-paths',
      classes: ['sheet'],
      template: 'modules/token-variants/templates/forgeSearchPaths.html',
      resizable: true,
      minimizable: false,
      closeOnSubmit: false,
      title: game.i18n.localize('token-variants.settings.search-paths.Name'),
      width: 592,
      height: 'auto',
      scrollY: ['ol.token-variant-table'],
      dragDrop: [{ dragSelector: null, dropSelector: null }],
    });
  }

  async getData(options) {
    if (!this.object.paths) this.object.paths = await this._getPaths();

    const paths = this.object.paths.map((path) => {
      const r = {};
      r.text = path.text;
      r.cache = path.cache;
      r.share = path.share;
      r.types = path.types.join(',');
      r.config = JSON.stringify(path.config ?? {});
      return r;
    });

    const data = super.getData(options);
    data.paths = paths;
    data.apiKey = this.apiKey;
    return data;
  }

  async _getPaths() {
    const forgePaths = deepClone(TVA_CONFIG.forgeSearchPaths) || {};
    this.userId = typeof ForgeAPI !== 'undefined' ? await ForgeAPI.getUserId() : 'tempUser'; // TODO
    this.apiKey = forgePaths[this.userId]?.apiKey;
    return forgePaths[this.userId]?.paths || [];
  }

  /**
   * @param {JQuery} html
   */
  activateListeners(html) {
    super.activateListeners(html);
    html.find('a.create-path').click(this._onCreatePath.bind(this));
    $(html).on('click', 'a.select-category', showPathSelectCategoryDialog.bind(this));
    $(html).on('click', 'a.select-config', showPathSelectConfigForm.bind(this));
    html.find('a.delete-path').click(this._onDeletePath.bind(this));
    html.find('button.reset').click(this._onReset.bind(this));
    html.find('button.update').click(this._onUpdate.bind(this));
    $(html).on('click', '.path-image.source-icon a', this._onBrowseFolder.bind(this));
  }

  /**
   * Open a FilePicker so the user can select a local folder to use as an image source
   */
  async _onBrowseFolder(event) {
    const pathInput = $(event.target).closest('.table-row').find('.path-text input');

    new FilePicker({
      type: 'folder',
      activeSource: 'forgevtt',
      current: pathInput.val(),
      callback: (path, fp) => {
        if (fp.activeSource !== 'forgevtt') {
          ui.notifications.warn("Token Variant Art: Only 'Assets Library' paths are supported");
        } else {
          pathInput.val(fp.result.target);
        }
      },
    }).render(true);
  }

  async _onCreatePath(event) {
    event.preventDefault();
    await this._onSubmit(event);

    this.object.paths.push({
      text: '',
      cache: true,
      share: true,
      types: ['Portrait', 'Token', 'PortraitAndToken'],
    });
    this.render();
  }

  async _onDeletePath(event) {
    event.preventDefault();
    await this._onSubmit(event);

    const li = event.currentTarget.closest('.table-row');
    this.object.paths.splice(li.dataset.index, 1);
    this.render();
  }

  _onReset(event) {
    event.preventDefault();
    this.object.paths = this._getPaths();
    this.render();
  }

  async _onUpdate(event) {
    event.preventDefault();
    await this._onSubmit(event);
    this._updatePaths();
  }

  async _updateObject(event, formData) {
    const expanded = expandObject(formData);
    expanded.paths = expanded.hasOwnProperty('paths') ? Object.values(expanded.paths) : [];
    expanded.paths.forEach((path, index) => {
      this.object.paths[index] = {
        text: path.text,
        cache: path.cache,
        share: path.share,
        source: path.source,
        types: path.types.split(','),
      };
      if (path.config) {
        try {
          path.config = JSON.parse(path.config);
          if (!isEmpty(path.config)) {
            this.object.paths[index].config = path.config;
          }
        } catch (e) {}
      }
    });
    this.apiKey = expanded.apiKey;
  }

  _cleanPaths() {
    // Cleanup empty and duplicate paths
    let uniquePaths = new Set();
    let paths = this.object.paths.filter((path) => {
      if (!path.text || uniquePaths.has(path.text)) return false;
      uniquePaths.add(path.text);
      return true;
    });
    return paths;
  }

  _updatePaths() {
    if (this.userId) {
      const forgePaths = deepClone(TVA_CONFIG.forgeSearchPaths) || {};
      forgePaths[this.userId] = {
        paths: this._cleanPaths(),
        apiKey: this.apiKey,
      };

      if (game.user.isGM) {
        updateSettings({ forgeSearchPaths: forgePaths });
      } else {
        // Workaround for forgeSearchPaths setting to be updated by non-GM clients
        const message = {
          handlerName: 'forgeSearchPaths',
          args: forgePaths,
          type: 'UPDATE',
        };
        game.socket?.emit('module.token-variants', message);
      }
    }
  }

  async close(options = {}) {
    await this._onSubmit(event);
    this._updatePaths();
    return super.close(options);
  }
}
