import { Component, Prop, Watch } from 'vue-property-decorator';
import Vue from 'vue';
import { ConditionType } from '@components/common/base-search-bar/index.ts';
import { i18n } from '@plugins/i18n';
import ServicesSearchBar from './components/search-bar.vue';
import DigitalRegulationsFormDialog from '@components/services/components/digital-regulations-form-dialog.vue';
import ImportDialog from '@components/services/components/import-services-dialog.vue';
import { pushRoute } from '@utils/routes';
import { Service, ServiceApi } from '@openapi/registry-service';
import get from 'lodash/get';
import cloneDeep from 'lodash/cloneDeep';
import { WorkflowServiceApi } from '@openapi/wf';
import {notifyError, notifySuccess} from '@utils/notify';
import { USER_SCOPES } from '@/constants/entities/Scope';
import { ComponentApi } from '@openapi/nexus-transfer';

const serviceApi = new ServiceApi();
const wfApi = new WorkflowServiceApi();
const ntApi = new ComponentApi();

@Component({
  components: {
    ServicesSearchBar,
    DigitalRegulationsFormDialog,
    ImportDialog,
  },
})
class Services extends Vue {
  @Prop() searchQuery: ServiceSearchQuery | undefined;

  private dialogCreate = false;
  private newServiceName = '';
  private loading = false;
  private sortByDefault = 'modified';
  private servicesLoading: { [service: string]: boolean } = {};
  private importNexus = false
  private serviceFile = null
  private serviceCode = ''
  private buttonNexusFlag = window.location.host !== 'pgs2.gosuslugi.ru'

  @Watch('importNexus')
  importNexusChange () {
    this.serviceCode = ''
    this.serviceFile = null
  }

  model = {
    loading: false,
    pagination: {
      descending:
        this.$route.query.descending === undefined
          ? true
          : this.$route.query.descending === 'true',
      rowsPerPage: this.$route.query.rowsPerPage
        ? Number(this.$route.query.rowsPerPage)
        : 10,
      sortBy: this.$route.query.sortBy
        ? this.$route.query.sortBy
        : this.sortByDefault,
      rowsNumber: 0,
      page: this.$route.query.page ? Number(this.$route.query.page) : 1,
    },
    services: [] as Service[],
    visibleColumns: ['name'],
    query: '',
  };

  importServiceData: serviceImportModel | null = null;

  queryString = '';
  fulltextString = '';

  importDialog = false;

  importAllDialog = false;

  userTask = '';

  attributes = [
    {
      attribute: 'description',
      attributeName: i18n.t('services.description'),
      conditionType: ConditionType.string,
      value: '',
    },
  ];

  private get stateColorMap() {
    return this.$store.getters['registryService/services/stateColorMap'];
  }

  private get columns() {
    return [
      {
        align: 'left',
        field: (i: any) => i,
        formatField: 'shortName',
        handler: (item: any, options: any) => {
          pushRoute(
            this.$router,
            {
              name: 'cards',
              params: {
                id: item.id,
                path: 'services',
              },
              query: {
                active: 'basic',
                components: this.$store.getters[
                  'cardComponents/services/components'
                ],
              },
            },
            options?.targetBlank
          );
        },
        label: this.$t('services.shortName'),
        name: 'shortName',
        style: 'white-space: normal;',
        required: true,
        sortable: true,
      },
      {
        align: 'left',
        field: 'fullName',
        label: this.$t('services.fullName'),
        name: 'fullName',
        style: 'white-space: pre-wrap',
        required: true,
        sortable: true,
      },
      {
        align: 'left',
        field: 'petitionType',
        label: this.$t('services.petitionType'),
        name: 'petitionType',
        required: true,
        sortable: true,
      },
      {
        align: 'left',
        field: 'state',
        label: this.$t('services.state'),
        name: 'state',
        style: 'white-space: pre-wrap',
        required: true,
        sortable: true,
      },
    ];
  }

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

  get isServicesConstruct(): boolean {
    return this.$AC.haveScope(USER_SCOPES.SERVICES_CONSTRUCT);
  }

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

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

  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.page = val.pagination.page;
      this.model.pagination.sortBy =
        val.pagination.sortBy === null
          ? this.sortByDefault
          : val.pagination.sortBy;
    }

    const pagination = {
      sort: '',
    };

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

  private pending = 0;

  private importDS() {
    this.importDialog = true;
  }

  private async importServices() {
    this.loading = true;

    const currentUser = this.$store.getters['oidcClient/currentUser'];
    const userId = currentUser?.sub;

    await wfApi
      .start({
        processKey: 'BatchZipServiceImportFromNexusProcess',
        data: { userId },
      })
      .then(({ data: { traceId } }) => {
        const handler = (e: any) => {
          const data = JSON.parse(get(e, 'data', '{}'));
          if (data.traceId === traceId) {
            const outData: serviceImportModel = get(
              data,
              'body.userTask.outData',
              null
            );
            if (outData?.info && this.importServiceData) {
              const newImportService = cloneDeep(this.importServiceData);
              if (!newImportService.info) newImportService.info = {};

              Object.keys(outData.info).forEach((newInfo) => {
                if (newImportService.info?.[newInfo]) {
                  newImportService.info[newInfo] = {
                    ...newImportService.info?.[newInfo],
                    ...outData.info?.[newInfo],
                  };
                } else {
                  newImportService.info[newInfo] = outData.info[newInfo];
                }

                this.importServiceData = newImportService;
                const logsLoading = cloneDeep(this.servicesLoading);
                delete logsLoading[newInfo];
                this.servicesLoading = logsLoading;
              });
              this.userTask = get(data, 'body.userTask.taskId', '');
            } else if (outData && outData.available) {
              this.importAllDialog = true;
              this.importServiceData = outData;
              this.userTask = get(data, 'body.userTask.taskId', '');
              this.loading = false;
              this.servicesLoading = {};
            }
            const succesedImport: serviceImportModel = get(
              data,
              'body.userTask.outData.succesedImport'
            );
            const failedImport: serviceImportModel = get(
              data,
              'body.userTask.outData.failedImport'
            );
            if (
              succesedImport ||
              failedImport ||
              get(data, 'body.success') === false
            ) {
              this.$websockets.removeListener(handler);
            }
          }
        };

        this.$websockets.addListener(handler);
      });
  }

  private createService() {
    if (!this.newServiceName) {
      return;
    }
    const data = {
      shortName: this.newServiceName,
      state: 'draft',
    };

    serviceApi
      .createService([data as Service])
      .then((response) => {
        const { data } = response;
        if (!data.objectIds) throw new Error('Created Service have no id');
        this.$router.push({
          name: 'cards',
          params: {
            id: data.objectIds[0],
            path: 'services',
          },
          query: {
            active: 'basic',
            components: this.$store.getters[
              'cardComponents/services/components'
            ],
          },
        });
      })
      .catch((e) => {
        notifyError(e.message.toString());
      });
  }

  private async fetch(q?: ServiceQuery) {
    if (typeof q !== 'undefined') {
      this.queryString = q?.query || '';
      this.fulltextString = q?.fulltext || '';
    }

    if (this.pending) {
      this.pending++;
      return;
    }

    this.pending = 1;
    this.model.loading = true;

    await serviceApi
      .pagingService(
        this.model.pagination.page,
        this.model.pagination.rowsPerPage,
        undefined,
        this.fulltextString,
        `${this.model.pagination.descending ? '-' : '+'}${
          this.model.pagination.sortBy
        }`
      )
      .then(({ data }) => {
        if (data.totalRows && data.records) {
          this.model.pagination.rowsNumber = data.totalRows;
          this.model.services = data.records;
        }
      })
      .catch((e) => {
        notifyError(e.message.toString());
      })
      .finally(() => {
        this.model.loading = false;
      });

    if (this.pending > 1) {
      this.pending = 0;
      await this.fetch();

      return;
    }
    this.pending = 0;
  }

  private async importToNexus() {
    try {
      await ntApi.validateServiceArchive(this.serviceCode, this.serviceFile)
      await ntApi.uploadServiceArchive(this.serviceCode, this.serviceFile)
      notifySuccess('Импорт услуги в Nexus произведен успешно')
    } catch (e) {
      notifyError(e.response.data.error)
    }
  }

}

export default Services;

declare interface ServiceQuery {
  query: string;
  fulltext: string;
}

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

export interface serviceImportModel {
  available: ServiceItemsMap;
  outdate: Array<string>;
  info: ServiceInfoMap;
  formCount: number;
  processCount: number;
  parsed: boolean;
}

export type ServiceInfoMap = {
  [service: string]: {
    [version: string]: ServiceVersion[];
  };
};
export type ServiceVersion = {
  version: string;
  date: string;
  description: string;
};
export type ServiceItemsMap = {
  [index: string]: string[];
};
