<script>
import { pickBy, isEmpty, mapValues } from 'lodash';
import { mapActions } from 'vuex';
import { getIdFromGraphQLId, isGid } from '~/graphql_shared/utils';
import { updateHistory, setUrlParams } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants';
import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
import { AssigneeFilterType } from '~/boards/constants';

export default {
  i18n: {
    search: __('Search'),
    label: __('Label'),
    author: __('Author'),
  },
  components: { FilteredSearch },
  inject: ['initialFilterParams'],
  props: {
    tokens: {
      type: Array,
      required: true,
    },
    eeFilters: {
      required: false,
      type: Object,
      default: () => ({}),
    },
  },
  data() {
    return {
      filterParams: this.initialFilterParams,
    };
  },
  computed: {
    getFilteredSearchValue() {
      const {
        authorUsername,
        labelName,
        assigneeUsername,
        assigneeId,
        search,
        milestoneTitle,
        iterationId,
        types,
        weight,
        epicId,
        myReactionEmoji,
        releaseTag,
        confidential,
      } = this.filterParams;
      const filteredSearchValue = [];

      if (authorUsername) {
        filteredSearchValue.push({
          type: 'author',
          value: { data: authorUsername, operator: '=' },
        });
      }

      if (assigneeUsername) {
        filteredSearchValue.push({
          type: 'assignee',
          value: { data: assigneeUsername, operator: '=' },
        });
      }

      if (assigneeId) {
        filteredSearchValue.push({
          type: 'assignee',
          value: { data: assigneeId, operator: '=' },
        });
      }

      if (types) {
        filteredSearchValue.push({
          type: 'type',
          value: { data: types, operator: '=' },
        });
      }

      if (labelName?.length) {
        filteredSearchValue.push(
          ...labelName.map((label) => ({
            type: 'label',
            value: { data: label, operator: '=' },
          })),
        );
      }

      if (milestoneTitle) {
        filteredSearchValue.push({
          type: 'milestone',
          value: { data: milestoneTitle, operator: '=' },
        });
      }

      if (iterationId) {
        filteredSearchValue.push({
          type: 'iteration',
          value: { data: iterationId, operator: '=' },
        });
      }

      if (weight) {
        filteredSearchValue.push({
          type: 'weight',
          value: { data: weight, operator: '=' },
        });
      }

      if (myReactionEmoji) {
        filteredSearchValue.push({
          type: 'my-reaction',
          value: { data: myReactionEmoji, operator: '=' },
        });
      }

      if (releaseTag) {
        filteredSearchValue.push({
          type: 'release',
          value: { data: releaseTag, operator: '=' },
        });
      }

      if (confidential !== undefined) {
        filteredSearchValue.push({
          type: 'confidential',
          value: { data: confidential },
        });
      }

      if (epicId) {
        filteredSearchValue.push({
          type: 'epic',
          value: { data: epicId, operator: '=' },
        });
      }

      if (this.filterParams['not[authorUsername]']) {
        filteredSearchValue.push({
          type: 'author',
          value: { data: this.filterParams['not[authorUsername]'], operator: '!=' },
        });
      }

      if (this.filterParams['not[milestoneTitle]']) {
        filteredSearchValue.push({
          type: 'milestone',
          value: { data: this.filterParams['not[milestoneTitle]'], operator: '!=' },
        });
      }

      if (this.filterParams['not[iteration_id]']) {
        filteredSearchValue.push({
          type: 'iteration_id',
          value: { data: this.filterParams['not[iteration_id]'], operator: '!=' },
        });
      }

      if (this.filterParams['not[weight]']) {
        filteredSearchValue.push({
          type: 'weight',
          value: { data: this.filterParams['not[weight]'], operator: '!=' },
        });
      }

      if (this.filterParams['not[assigneeUsername]']) {
        filteredSearchValue.push({
          type: 'assignee',
          value: { data: this.filterParams['not[assigneeUsername]'], operator: '!=' },
        });
      }

      if (this.filterParams['not[labelName]']) {
        filteredSearchValue.push(
          ...this.filterParams['not[labelName]'].map((label) => ({
            type: 'label',
            value: { data: label, operator: '!=' },
          })),
        );
      }

      if (this.filterParams['not[types]']) {
        filteredSearchValue.push({
          type: 'type',
          value: { data: this.filterParams['not[types]'], operator: '!=' },
        });
      }

      if (this.filterParams['not[epicId]']) {
        filteredSearchValue.push({
          type: 'epic',
          value: { data: this.filterParams['not[epicId]'], operator: '!=' },
        });
      }

      if (this.filterParams['not[myReactionEmoji]']) {
        filteredSearchValue.push({
          type: 'my-reaction',
          value: { data: this.filterParams['not[myReactionEmoji]'], operator: '!=' },
        });
      }

      if (this.filterParams['not[releaseTag]']) {
        filteredSearchValue.push({
          type: 'release',
          value: { data: this.filterParams['not[releaseTag]'], operator: '!=' },
        });
      }

      if (search) {
        filteredSearchValue.push(search);
      }

      return filteredSearchValue;
    },
    urlParams() {
      const {
        authorUsername,
        labelName,
        assigneeUsername,
        assigneeId,
        search,
        milestoneTitle,
        types,
        weight,
        epicId,
        myReactionEmoji,
        iterationId,
        releaseTag,
        confidential,
      } = this.filterParams;
      let notParams = {};

      if (Object.prototype.hasOwnProperty.call(this.filterParams, 'not')) {
        notParams = pickBy(
          {
            'not[label_name][]': this.filterParams.not.labelName,
            'not[author_username]': this.filterParams.not.authorUsername,
            'not[assignee_username]': this.filterParams.not.assigneeUsername,
            'not[types]': this.filterParams.not.types,
            'not[milestone_title]': this.filterParams.not.milestoneTitle,
            'not[weight]': this.filterParams.not.weight,
            'not[epic_id]': this.filterParams.not.epicId,
            'not[my_reaction_emoji]': this.filterParams.not.myReactionEmoji,
            'not[iteration_id]': this.filterParams.not.iterationId,
            'not[release_tag]': this.filterParams.not.releaseTag,
          },
          undefined,
        );
      }

      return mapValues(
        {
          ...notParams,
          author_username: authorUsername,
          'label_name[]': labelName,
          assignee_username: assigneeUsername,
          assignee_id: assigneeId,
          milestone_title: milestoneTitle,
          iteration_id: iterationId,
          search,
          types,
          weight,
          epic_id: isGid(epicId) ? getIdFromGraphQLId(epicId) : epicId,
          my_reaction_emoji: myReactionEmoji,
          release_tag: releaseTag,
          confidential,
        },
        (value) => {
          if (value || value === false) {
            // note: need to check array for labels.
            if (Array.isArray(value)) {
              return value.map((valueItem) => encodeURIComponent(valueItem));
            }

            return encodeURIComponent(value);
          }

          return value;
        },
      );
    },
  },
  created() {
    if (!isEmpty(this.eeFilters)) {
      this.filterParams = this.eeFilters;
    }
  },
  methods: {
    ...mapActions(['performSearch']),
    handleFilter(filters) {
      this.filterParams = this.getFilterParams(filters);

      updateHistory({
        url: setUrlParams(this.urlParams, window.location.href, true, false, true),
        title: document.title,
        replace: true,
      });

      this.performSearch();
    },
    getFilterParams(filters = []) {
      const notFilters = filters.filter((item) => item.value.operator === '!=');
      const equalsFilters = filters.filter(
        (item) => item?.value?.operator === '=' || item.type === FILTERED_SEARCH_TERM,
      );

      return { ...this.generateParams(equalsFilters), not: { ...this.generateParams(notFilters) } };
    },
    generateParams(filters = []) {
      const filterParams = {};
      const labels = [];
      const plainText = [];

      filters.forEach((filter) => {
        switch (filter.type) {
          case 'author':
            filterParams.authorUsername = filter.value.data;
            break;
          case 'assignee':
            if (Object.values(AssigneeFilterType).includes(filter.value.data)) {
              filterParams.assigneeId = filter.value.data;
            } else {
              filterParams.assigneeUsername = filter.value.data;
            }
            break;
          case 'type':
            filterParams.types = filter.value.data;
            break;
          case 'label':
            labels.push(filter.value.data);
            break;
          case 'milestone':
            filterParams.milestoneTitle = filter.value.data;
            break;
          case 'iteration':
            filterParams.iterationId = filter.value.data;
            break;
          case 'weight':
            filterParams.weight = filter.value.data;
            break;
          case 'epic':
            filterParams.epicId = filter.value.data;
            break;
          case 'my-reaction':
            filterParams.myReactionEmoji = filter.value.data;
            break;
          case 'release':
            filterParams.releaseTag = filter.value.data;
            break;
          case 'confidential':
            filterParams.confidential = filter.value.data;
            break;
          case 'filtered-search-term':
            if (filter.value.data) plainText.push(filter.value.data);
            break;
          default:
            break;
        }
      });

      if (labels.length) {
        filterParams.labelName = labels;
      }

      if (plainText.length) {
        filterParams.search = plainText.join(' ');
      }

      return filterParams;
    },
  },
};
</script>

<template>
  <filtered-search
    class="gl-w-full"
    namespace=""
    :tokens="tokens"
    :search-input-placeholder="$options.i18n.search"
    :initial-filter-value="getFilteredSearchValue"
    @onFilter="handleFilter"
  />
</template>
