import PlaceableTab from "./placeable-tab.mjs";
import FilterMenu from "../../ux/filter-menu.mjs";

/**
 * The Wall-specific placeables tab.
 * @extends {PlaceableTab}
 */
export default class WallTab extends PlaceableTab {
  /** @override */
  static DEFAULT_OPTIONS = {
    actions: {
      selectGroup: WallTab.#onSelectGroup
    }
  };

  /** @override */
  static DIRECTORY_PARTIAL = "templates/sidebar/tabs/placeable/walls.hbs";

  /* -------------------------------------------- */
  /*  Rendering                                   */
  /* -------------------------------------------- */

  /** @inheritDoc */
  async _prepareDirectoryContext(context, options) {
    context = await super._prepareDirectoryContext(context, options);
    const { CATEGORY_COLORS } = getDocumentClass("Wall");
    const groups = {};
    for ( const entry of context.entries ) {
      const { category } = entry;
      const color = CATEGORY_COLORS[category];
      const group = groups[category] ??= {
        category, color,
        label: _loc(`SIDEBAR.PLACEABLES.WALLS.${category}`), entries: []
      };
      group.entries.push(entry);
    }
    context.groups = ["secret", "door", "window", "invisible", "ethereal", "terrain", "normal", "blank"].reduce((arr, cat) => {
      const group = groups[cat];
      if ( group?.entries.length ) arr.push(group);
      return arr;
    }, []);
    return context;
  }

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

  /** @inheritDoc */
  async _prepareEntry(entry, context) {
    context = await super._prepareEntry(entry, context);
    context.category = entry.getWallCategory();
    return context;
  }

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

  /** @inheritDoc */
  async _prepareSearchContext(context, options) {
    context = await super._prepareSearchContext(context, options);
    context.filters.findSplice(f => f.action === "openFilter", {
      action: "filterByCategory", active: !!this._filterState.categories?.size,
      cssClass: "fa-solid fa-shapes", tooltip: "SIDEBAR.PLACEABLES.WALLS.filterByCategory"
    });
    return context;
  }

  /* -------------------------------------------- */
  /*  Event Listeners & Handlers                  */
  /* -------------------------------------------- */

  /** @inheritDoc */
  _attachFrameListeners() {
    super._attachFrameListeners();
    new FilterMenu.implementation(this.element, "search [data-action=filterByCategory]", {
      menuItems: this.#getCategoryFilterOptions.bind(this)
    });
  }

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

  /**
   * Get options for filtering by wall category.
   * @returns {ContextMenuEntry[]}
   */
  #getCategoryFilterOptions() {
    const { CATEGORY_COLORS } = getDocumentClass("Wall");
    const entries = Object.keys(CATEGORY_COLORS).map(cat => ({
      label: _loc(`SIDEBAR.PLACEABLES.WALLS.${cat}`),
      icon: this._filterState.categories?.has(cat) ? "fa-solid fa-check" : "fa-solid",
      onClick: () => this._onFilterByCategory(cat)
    }));
    entries.push({
      label: _loc("SIDEBAR.PLACEABLES.ACTIONS.Clear"),
      icon: "fa-solid fa-xmark",
      onClick: () => {
        this._onFilterByCategory(null);
        ui.context.close();
      },
      group: "state"
    });
    return entries;
  }

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

  /** @inheritDoc */
  _matchesFilter(entry) {
    const { categories=new Set() } = this._filterState;
    return !categories.size || categories.has(entry.getWallCategory());
  }

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

  /**
   * Handle adjusting the category filter.
   * @param {string} cat  The wall category to filter by.
   * @protected
   */
  _onFilterByCategory(cat) {
    const categories = this._filterState.categories ??= new Set();
    if ( cat === null ) categories.clear();
    else if ( categories.has(cat) ) categories.delete(cat);
    else categories.add(cat);
    this.element.querySelector("search [data-action=filterByCategory]").ariaPressed = String(!!categories.size);
    this._applyFilters();
  }

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

  /**
   * Handle selecting a group of objects.
   * @this {WallTab}
   * @param {PointerEvent} event  The triggering event.
   * @param {HTMLElement} target  The action target.
   */
  static #onSelectGroup(event, target) {
    const { category } = target.closest("[data-category]").dataset;
    const [release, control] = this.layer.placeables.partition(w => w.document.getWallCategory() === category);
    if ( !event.shiftKey ) release.forEach(w => w.release({ renderSidebar: false }));
    control.forEach(w => w.control({ renderSidebar: false, releaseOthers: false }));
    ui.placeables.render();
    if ( game.activeTool === "select" ) ui.placeablesPalette?.render();
  }
}
