/**
 * The Application responsible for configuring a single ActiveEffect document within a parent Actor or Item.
 * @extends {DocumentSheet}
 *
 * @param {ActiveEffect} object             The target active effect being configured
 * @param {DocumentSheetOptions} [options]  Additional options which modify this application instance
 */
class ActiveEffectConfig extends DocumentSheet {

  /** @override */
  static get defaultOptions() {
    return foundry.utils.mergeObject(super.defaultOptions, {
      classes: ["sheet", "active-effect-sheet"],
      template: "templates/sheets/active-effect-config.html",
      width: 580,
      height: "auto",
      tabs: [{navSelector: ".tabs", contentSelector: "form", initial: "details"}]
    });
  }

  /* ----------------------------------------- */

  /** @override */
  async getData(options={}) {
    const context = await super.getData(options);
    context.descriptionHTML = await TextEditor.enrichHTML(this.object.description, {secrets: this.object.isOwner});
    const legacyTransfer = CONFIG.ActiveEffect.legacyTransferral;
    const labels = {
      transfer: {
        name: game.i18n.localize(`EFFECT.Transfer${legacyTransfer ? "Legacy" : ""}`),
        hint: game.i18n.localize(`EFFECT.TransferHint${legacyTransfer ? "Legacy" : ""}`)
      }
    };

    // Status Conditions
    const statuses = CONFIG.statusEffects.map(s => {
      return {
        id: s.id,
        label: game.i18n.localize(s.name ?? /** @deprecated since v12 */ s.label),
        selected: context.data.statuses.includes(s.id) ? "selected" : ""
      };
    });

    // Return rendering context
    return foundry.utils.mergeObject(context, {
      labels,
      effect: this.object, // Backwards compatibility
      data: this.object,
      isActorEffect: this.object.parent.documentName === "Actor",
      isItemEffect: this.object.parent.documentName === "Item",
      submitText: "EFFECT.Submit",
      statuses,
      modes: Object.entries(CONST.ACTIVE_EFFECT_MODES).reduce((obj, e) => {
        obj[e[1]] = game.i18n.localize(`EFFECT.MODE_${e[0]}`);
        return obj;
      }, {})
    });
  }

  /* ----------------------------------------- */

  /** @override */
  activateListeners(html) {
    super.activateListeners(html);
    html.find(".effect-control").click(this._onEffectControl.bind(this));
  }

  /* ----------------------------------------- */

  /**
   * Provide centralized handling of mouse clicks on control buttons.
   * Delegate responsibility out to action-specific handlers depending on the button action.
   * @param {MouseEvent} event      The originating click event
   * @private
   */
  _onEffectControl(event) {
    event.preventDefault();
    const button = event.currentTarget;
    switch ( button.dataset.action ) {
      case "add":
        return this._addEffectChange();
      case "delete":
        button.closest(".effect-change").remove();
        return this.submit({preventClose: true}).then(() => this.render());
    }
  }

  /* ----------------------------------------- */

  /**
   * Handle adding a new change to the changes array.
   * @private
   */
  async _addEffectChange() {
    const idx = this.document.changes.length;
    return this.submit({preventClose: true, updateData: {
      [`changes.${idx}`]: {key: "", mode: CONST.ACTIVE_EFFECT_MODES.ADD, value: ""}
    }});
  }

  /* ----------------------------------------- */

  /** @inheritdoc */
  _getSubmitData(updateData={}) {
    const fd = new FormDataExtended(this.form, {editors: this.editors});
    let data = foundry.utils.expandObject(fd.object);
    if ( updateData ) foundry.utils.mergeObject(data, updateData);
    data.changes = Array.from(Object.values(data.changes || {}));
    data.statuses ??= [];
    return data;
  }
}
