import { Component, Prop, Watch } from 'vue-property-decorator';
import Vue from 'vue';
import NotificationsSearchBar from './components/search-bar.vue';
import { Event, EventsApi } from '@openapi/notifier-registry';
import get from 'lodash/get';

import { Notification, NotificationsApi } from '@openapi/idm';
import { USER_SCOPES } from '@/constants/entities/Scope';
import { notifyError } from '@utils/notify';

const notificationsApi = new NotificationsApi();

@Component({
  components: {
    NotificationsSearchBar,
  },
})
export default class Notifications extends Vue {
  @Prop() searchQuery: NotificationsSearchQuery | undefined;
  USER_SCOPES = USER_SCOPES;

  model = {
    loading: false,
    pagination: {
      descending: true,
      rowsPerPage: 10,
      sortBy: 'modified',
      rowsNumber: 0,
      page: 1,
    },
    notifications: [] as Notification[],
    query: '',
    onlyMy: true, // FIXME: Deprecated
  };

  private inputSearch = '';

  private eventList: Array<Event> = [];

  private eventsService = new EventsApi();

  private get columns() {
    return [
      {
        align: 'left',
        field: (i: any) => i,
        handler: (val: any) => {
          this.$router.push({
            name: 'cards',
            params: {
              id: val?.id,
              path: 'notifications',
            },
            query: {
              components: this.$store.getters[
                'cardComponents/notifications/components'
              ],
              active: 'settings',
            },
          });
        },
        formatField: 'title',
        label: this.$t('notifications.name'),
        name: 'title',
        style: 'white-space: normal;',
        required: true,
        sortable: true,
      },
      {
        align: 'left',
        label: this.$t('notifications.role'),
        field: 'roles',
        formatField: 'displayName',
        defaultFormatField: 'name',
        name: 'roles',
        icon: 'o_group',
        required: true,
        sortable: true,
      },
      {
        align: 'left',
        field: (val: any) =>
          this.eventList.find((event) => event.id === val.eventId)?.description,
        label: this.$t('notifications.event'),
        name: 'event',
        required: true,
        sortable: true,
      },
    ];
  }

  private get sort(): string {
    return `${this.model.pagination.descending ? '-' : '+'}${
      this.model.pagination.sortBy
    }`;
  }

  private saveData(): void {
    const query = [];

    if (this.inputSearch) {
      query.push(`(${this.inputSearch})`);
    }
  }

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

  private init(val: any = null): void {
    if (
      get(
        {
          val,
        },
        'val.pagination'
      )
    ) {
      this.model.pagination.descending = val.pagination.descending;
      this.model.pagination.rowsPerPage = val.pagination.rowsPerPage;
      this.model.pagination.sortBy = val.pagination.sortBy;
      this.model.pagination.page = val.pagination.page;
    }

    const pagination = {
      sort: '',
    };

    if (this.sort) {
      pagination.sort = this.sort;
    }
    this.fetch();
  }

  private pending = 0;

  private createNotification() {
    try {
      const notificationSoketListenner = (e: MessageEvent) => {
        const data = JSON.parse(get(e, 'data', '{}'));
        if (get(data, 'body.type') === 'task' && get(data, 'traceId')) {
          this.$websockets.removeListener(notificationSoketListenner);

          this.$router.push({
            name: 'stepper',
            params: {
              traceId: get(data, 'traceId'),
            },
            query: {
              taskId: get(data, 'body.userTask.taskId', null),
            },
          });
        }
      };

      this.$websockets.addListener(notificationSoketListenner);

      this.$store.dispatch('wf/processes/dispatchProcess', {
        processKey: 'CreateDomainNotificationsProcess',
      });
    } catch (e) {
      notifyError(e.message.toString());
    }
  }

  private async getNotifications(
    handler?: 'my' | 'managed' | 'myRegion',
    query?: string
  ) {
    const arrQuery = [this.inputSearch || null, this.model.query];

    const currentQuery = arrQuery
      .filter((filter: string | null) => !!filter)
      .join(' and ');

    const {
      records: paging,
      totalRows,
    } = await notificationsApi
      .pagingNotifications(
        handler,
        this.model.pagination.page,
        this.model.pagination.rowsPerPage,
        query,
        currentQuery,
        `${this.model.pagination.descending ? '-' : '+'}${
          this.model.pagination.sortBy
        }`,
        'roles'
      )
      .then(({ data }) => data);
    this.model.notifications = paging ?? [];
    this.model.pagination.rowsNumber = totalRows ?? 0;
  }

  private async fetch(q?: string) {
    if (typeof q !== 'undefined') {
      this.inputSearch = q;
    }
    if (this.pending) {
      this.pending++;

      return;
    }
    this.pending = 1;

    this.model.loading = true;

    try {
      if (this.$AC.haveScope(USER_SCOPES.CLOUD_ADMIN)) {
        await this.getNotifications(undefined, undefined);
      } else if (this.$AC.haveScope(USER_SCOPES.REGION_ADMIN)) {
        await this.getNotifications('myRegion', undefined);
      } else if (this.$AC.haveScope(USER_SCOPES.ORGANIZATION_ADMIN)) {
        await this.getNotifications('managed', undefined);
      } else if (
        this.$AC.haveOneOfScope([
          USER_SCOPES.ALLOCATE_PERMISSION_REG,
          USER_SCOPES.ALLOCATE_PERMISSION_SPEC,
        ])
      ) {
        const userId = this.$store.getters['oidcClient/currentUser'].sub;
        await this.getNotifications(undefined, `createdById=="${userId}"`);
      }
    } catch (e) {
      notifyError(e.message.toString());
    } finally {
      this.model.loading = false;
    }

    await this.model.notifications.forEach(async (element: any) => {
      const event = await this.eventsService
        .getEvent(element.eventId)
        .then((response) => response.data);
      this.eventList.push(event);
    });
    if (this.pending > 1) {
      this.pending = 0;
      await this.fetch();

      return;
    }
    this.pending = 0;
  }

  /**
   * Deprecated
   * FIXME: Удалить при понимании не использования
   * @private
   */
  @Watch('model.onlyMy')
  private onlyMyHandler(): void {
    this.model.pagination.page = 1;
    this.model.pagination.rowsNumber = 0;
    this.init();
  }
}

export interface NotificationsSearchQuery {
  status: string;
  search: string;
}
