import { Component, Mixins, Watch } from 'vue-property-decorator';
import { v4 } from 'uuid';
import findIndex from 'lodash/findIndex';
import first from 'lodash/first';
import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import isEqual from 'lodash/isEqual';
import last from 'lodash/last';

enum CloseMode {
  SOFT = 'soft',
  HARD = 'hard',
}
enum TabType {
  BPMN = 'bpmn',
  DMN = 'dmn', // isn't supported now
}

@Component({})
export default class UserTasksEditorComponent extends Mixins() {
  @Watch('schemas', {
    immediate: true,
  })
  private schemasHandler(val: string): void {
    if (!isEmpty(val)) {
      const schemas: string[] = val.split(',');

      this.closeAllTabs(CloseMode.HARD);

      schemas.forEach((schema) => {
        this.createTab(TabType.BPMN, schema);
      });
    }
  }

  private tabsLimit = 10;

  private tabId: string | null = null;

  private tabs: Tab[] = [];

  private get schemas(): string {
    return get(this.$route, 'query.schemas', '');
  }

  private created(): void {
    this.init();
  }

  private init(): void {
    this.initTabs();
  }

  private initTabs(): void {
    if (isEmpty(this.schemas)) {
      this.createTab(TabType.BPMN);
    }
  }

  private addTab(): void {
    this.createTab(TabType.BPMN);
  }

  private createTab(type: TabType, schema?: string): void {
    const tab: Tab = {
      component: () =>
        import('@components/processes/editor/components/bpmn/index.vue'),
      id: v4(),
      name: 'Новая вкладка',
      type,
    };

    if (!isEmpty(schema)) {
      tab.schema = schema;
    }

    this.tabs.push(tab);

    this.tabId = tab.id;
  }

  private closeTab(e: MouseEvent | null, id: string): void {
    if (!this.isSingleTab) {
      if (!isEmpty(e)) {
        e!.stopPropagation();
      }

      if (isEqual(this.tabId, id)) {
        if (this.isFirstTab) {
          this.goToNextTab();
        } else {
          this.goToPrevTab();
        }
      }

      this.tabs = this.tabs.filter((tab) => !isEqual(tab.id, id));
    }
  }

  private closeAllTabs(mode: CloseMode = CloseMode.SOFT): void {
    switch (mode) {
      case CloseMode.HARD: {
        this.tabs = [];

        break;
      }
      case CloseMode.SOFT: {
        this.tabs.forEach((tab) => {
          this.closeTab(null, tab.id);
        });

        break;
      }
    }
  }

  private goToNextTab(): void {
    this.tabId = get(this.tabs, `[${this.tabIndex + 1}].id`, null);
  }

  private goToPrevTab(): void {
    this.tabId = get(this.tabs, `[${this.tabIndex - 1}].id`, null);
  }

  private get isFirstTab(): boolean {
    return isEqual(get(first(this.tabs), 'id'), this.tabId);
  }

  private get isLastTab(): boolean {
    return isEqual(get(last(this.tabs), 'id'), this.tabId);
  }

  private get isSingleTab(): boolean {
    return isEqual(this.isFirstTab && this.isLastTab, true);
  }

  private get isTabsLimit(): boolean {
    return this.tabs.length >= this.tabsLimit;
  }

  private get tabIndex(): number {
    return typeof this.tabId === 'string'
      ? findIndex(this.tabs, { id: this.tabId })
      : -1;
  }
}

interface Tab {
  component: () => void;
  id: string;
  name: string;
  schema?: string;
  type: TabType;
}
