import _ from 'lodash';
import coreModule from '../../core_module';
import { SearchSrv } from 'app/core/services/search_srv';
import { contextSrv } from 'app/core/services/context_srv';
import appEvents from 'app/core/app_events';

export class SearchCtrl {
  isOpen: boolean;
  query: any;
  giveSearchFocus: number;
  selectedIndex: number;
  results: any;
  currentSearchId: number;
  showImport: boolean;
  dismiss: any;
  ignoreClose: any;
  isLoading: boolean;
  initialFolderFilterTitle: string;
  isEditor: string;
  hasEditPermissionInFolders: boolean;

  /** @ngInject */
  constructor($scope, private $location, private $timeout, private searchSrv: SearchSrv) {
    appEvents.on('show-dash-search', this.openSearch.bind(this), $scope);
    appEvents.on('hide-dash-search', this.closeSearch.bind(this), $scope);

    this.initialFolderFilterTitle = 'All';
    this.isEditor = contextSrv.isEditor;
    this.hasEditPermissionInFolders = contextSrv.hasEditPermissionInFolders;
  }

  closeSearch() {
    this.isOpen = this.ignoreClose;
  }

  openSearch(evt, payload) {
    if (this.isOpen) {
      this.closeSearch();
      return;
    }

    this.isOpen = true;
    this.giveSearchFocus = 0;
    this.selectedIndex = -1;
    this.results = [];
    this.query = { query: '', tag: [], starred: false };
    this.currentSearchId = 0;
    this.ignoreClose = true;
    this.isLoading = true;

    if (payload && payload.starred) {
      this.query.starred = true;
    }

    this.$timeout(() => {
      this.ignoreClose = false;
      this.giveSearchFocus = this.giveSearchFocus + 1;
      this.search();
    }, 100);
  }

  keyDown(evt) {
    if (evt.keyCode === 27) {
      this.closeSearch();
    }
    if (evt.keyCode === 40) {
      this.moveSelection(1);
    }
    if (evt.keyCode === 38) {
      this.moveSelection(-1);
    }
    if (evt.keyCode === 13) {
      const flattenedResult = this.getFlattenedResultForNavigation();
      const currentItem = flattenedResult[this.selectedIndex];

      if (currentItem) {
        if (currentItem.dashboardIndex !== undefined) {
          const selectedDash = this.results[currentItem.folderIndex].items[currentItem.dashboardIndex];

          if (selectedDash) {
            this.$location.search({});
            this.$location.path(selectedDash.url);
            this.closeSearch();
          }
        } else {
          const selectedFolder = this.results[currentItem.folderIndex];

          if (selectedFolder) {
            selectedFolder.toggle(selectedFolder);
          }
        }
      }
    }
  }

  onFilterboxClick() {
    this.giveSearchFocus = 0;
    this.preventClose();
  }

  preventClose() {
    this.ignoreClose = true;

    this.$timeout(() => {
      this.ignoreClose = false;
    }, 100);
  }

  moveSelection(direction) {
    if (this.results.length === 0) {
      return;
    }

    const flattenedResult = this.getFlattenedResultForNavigation();
    const currentItem = flattenedResult[this.selectedIndex];

    if (currentItem) {
      if (currentItem.dashboardIndex !== undefined) {
        this.results[currentItem.folderIndex].items[currentItem.dashboardIndex].selected = false;
      } else {
        this.results[currentItem.folderIndex].selected = false;
      }
    }

    if (direction === 0) {
      this.selectedIndex = -1;
      return;
    }

    const max = flattenedResult.length;
    const newIndex = (this.selectedIndex + direction) % max;
    this.selectedIndex = newIndex < 0 ? newIndex + max : newIndex;
    const selectedItem = flattenedResult[this.selectedIndex];

    if (selectedItem.dashboardIndex === undefined && this.results[selectedItem.folderIndex].id === 0) {
      this.moveSelection(direction);
      return;
    }

    if (selectedItem.dashboardIndex !== undefined) {
      if (!this.results[selectedItem.folderIndex].expanded) {
        this.moveSelection(direction);
        return;
      }

      this.results[selectedItem.folderIndex].items[selectedItem.dashboardIndex].selected = true;
      return;
    }

    if (this.results[selectedItem.folderIndex].hideHeader) {
      this.moveSelection(direction);
      return;
    }

    this.results[selectedItem.folderIndex].selected = true;
  }

  searchDashboards() {
    this.currentSearchId = this.currentSearchId + 1;
    const localSearchId = this.currentSearchId;
    const query = {
      ...this.query,
      tag: this.query.tag,
    };

    return this.searchSrv.search(query).then(results => {
      if (localSearchId < this.currentSearchId) {
        return;
      }
      this.results = results || [];
      this.isLoading = false;
      this.moveSelection(1);
    });
  }

  queryHasNoFilters() {
    const query = this.query;
    return query.query === '' && query.starred === false && query.tag.length === 0;
  }

  filterByTag(tag) {
    if (_.indexOf(this.query.tag, tag) === -1) {
      this.query.tag.push(tag);
      this.search();
    }
  }

  removeTag(tag, evt) {
    this.query.tag = _.without(this.query.tag, tag);
    this.search();
    this.giveSearchFocus = this.giveSearchFocus + 1;
    evt.stopPropagation();
    evt.preventDefault();
  }

  getTags = () => {
    return this.searchSrv.getDashboardTags();
  };

  onTagFiltersChanged = (tags: string[]) => {
    this.query.tag = tags;
    this.search();
  };

  clearSearchFilter() {
    this.query.tag = [];
    this.search();
  }

  showStarred() {
    this.query.starred = !this.query.starred;
    this.giveSearchFocus = this.giveSearchFocus + 1;
    this.search();
  }

  search() {
    this.showImport = false;
    this.selectedIndex = -1;
    this.searchDashboards();
  }

  folderExpanding() {
    this.moveSelection(0);
  }

  private getFlattenedResultForNavigation() {
    let folderIndex = 0;

    return _.flatMap(this.results, s => {
      let result = [];

      result.push({
        folderIndex: folderIndex,
      });

      let dashboardIndex = 0;

      result = result.concat(
        _.map(s.items || [], i => {
          return {
            folderIndex: folderIndex,
            dashboardIndex: dashboardIndex++,
          };
        })
      );

      folderIndex++;
      return result;
    });
  }
}

export function searchDirective() {
  return {
    restrict: 'E',
    templateUrl: 'public/app/core/components/search/search.html',
    controller: SearchCtrl,
    bindToController: true,
    controllerAs: 'ctrl',
    scope: {},
  };
}

coreModule.directive('dashboardSearch', searchDirective);
