import { computed } from "@ember/object";
import { next } from "@ember/runloop";
import { isPresent } from "@ember/utils";
import { classNames } from "@ember-decorators/component";
import { makeArray } from "discourse-common/lib/helpers";
import SelectKitComponent, {
  pluginApiIdentifiers,
  selectKitOptions,
} from "select-kit/components/select-kit";

@classNames("multi-select")
@selectKitOptions({
  none: "select_kit.default_header_text",
  clearable: true,
  filterable: true,
  filterIcon: null,
  closeOnChange: false,
  autoInsertNoneItem: false,
  headerComponent: "multi-select/multi-select-header",
  filterComponent: "multi-select/multi-select-filter",
  autoFilterable: true,
  caretDownIcon: "caretIcon",
  caretUpIcon: "caretIcon",
  useHeaderFilter: false,
})
@pluginApiIdentifiers(["multi-select"])
export default class MultiSelect extends SelectKitComponent {
  multiSelect = true;

  @computed("value.[]")
  get caretIcon() {
    const maximum = this.selectKit.options.maximum;
    return maximum && makeArray(this.value).length >= parseInt(maximum, 10)
      ? null
      : "plus";
  }

  search(filter) {
    return super
      .search(filter)
      .filter((content) => !makeArray(this.selectedContent).includes(content));
  }

  append(values) {
    const existingItems = values
      .map((value) => {
        const defaultItem = this.defaultItem(value, value);
        const existingItem =
          this.findValue(this.mainCollection, defaultItem) ||
          this.findName(this.mainCollection, defaultItem);
        if (!existingItem) {
          if (this.validateCreate(value, this.content)) {
            return value;
          }
        } else if (this.validateSelect(existingItem)) {
          return this.getValue(existingItem);
        }
      })
      .filter(Boolean);

    const newValues = makeArray(this.value).concat(existingItems);
    const newContent = makeArray(this.selectedContent).concat(
      makeArray(existingItems)
    );

    this.selectKit.change(newValues, newContent);
  }

  deselect(item) {
    this.clearErrors();

    const newContent = this.selectedContent.filter(
      (content) => this.getValue(item) !== this.getValue(content)
    );

    this.selectKit.change(
      this.valueProperty ? newContent.mapBy(this.valueProperty) : newContent,
      newContent
    );
  }

  select(value, item) {
    if (this.selectKit.hasSelection && this.selectKit.options.maximum === 1) {
      this.selectKit.deselectByValue(
        this.getValue(this.selectedContent.firstObject)
      );
      next(() => {
        this.selectKit.select(value, item);
      });
      return;
    }

    if (!isPresent(value)) {
      if (!this.validateSelect(this.selectKit.highlighted)) {
        return;
      }

      this.selectKit.change(
        makeArray(this.value).concat(
          makeArray(this.getValue(this.selectKit.highlighted))
        ),
        makeArray(this.selectedContent).concat(
          makeArray(this.selectKit.highlighted)
        )
      );
    } else {
      const existingItem = this.findValue(
        this.mainCollection,
        this.selectKit.valueProperty ? item : value
      );
      if (existingItem) {
        if (!this.validateSelect(item)) {
          return;
        }
      }

      const newValues = makeArray(this.value).concat(makeArray(value));
      const newContent = makeArray(this.selectedContent).concat(
        makeArray(item)
      );

      this.selectKit.change(
        [...new Set(newValues)],
        newContent.length
          ? newContent
          : makeArray(this.defaultItem(value, value))
      );
    }
  }

  @computed("value.[]", "content.[]", "selectKit.noneItem")
  get selectedContent() {
    const value = makeArray(this.value).map((v) =>
      this.selectKit.options.castInteger && this._isNumeric(v) ? Number(v) : v
    );

    if (value.length) {
      let content = [];

      value.forEach((v) => {
        if (this.selectKit.valueProperty) {
          const c = makeArray(this.content).findBy(
            this.selectKit.valueProperty,
            v
          );
          if (c) {
            content.push(c);
          }
        } else {
          if (makeArray(this.content).includes(v)) {
            content.push(v);
          }
        }
      });

      return this.selectKit.modifySelection(content);
    }

    return null;
  }

  _onKeydown(event) {
    if (
      event.code === "Enter" &&
      event.target.classList.contains("selected-name")
    ) {
      event.stopPropagation();
      this.selectKit.deselectByValue(event.target.dataset.value);
      return false;
    }

    if (event.code === "Backspace") {
      event.stopPropagation();

      const input = this.getFilterInput();
      if (input && input.value.length === 0) {
        const selected = this.element.querySelectorAll(
          ".select-kit-header .choice.select-kit-selected-name"
        );

        if (selected.length) {
          const lastSelected = selected[selected.length - 1];
          if (lastSelected) {
            if (lastSelected === document.activeElement) {
              this.deselect(this.selectedContent.lastObject);
            } else {
              lastSelected.focus();
            }
          }
        }
      }
    }

    return true;
  }
}