<template>
  <div>
    <q-card
      class="no-shadow q-pb-md q-gutter-y-md q-mx-md q-mt-md"
      v-if="card && !loading"
    >
      <div
        class="bg-grey-1 items-center justify-between row q-pa-md"
        style="border-radius: 0; padding: 16px"
      >
        <q-btn
          padding="xs"
          class="text-grey-7 q-mr-md"
          color="grey-3"
          icon="arrow_back"
          @click="goToServicesList()"
        />
        <div class="text-h6 text-grey-9 col q-pr-md">
          {{ cardModel.shortName }}
          <q-icon :name="icons.kcrImport" v-if="cardModel.kcrImport">
            <q-tooltip :delay="500">
              {{ $t('services.ServiceCart.kcrImport') }}
            </q-tooltip>
          </q-icon>

          <q-btn
            :icon="icons.epguImport"
            color="info"
            v-if="cardModel.state === 'inProgress' && !cardModel.epguImport"
            round
            flat
            @click="importFromXSD"
          >
            <q-tooltip :delay="500">
              {{ $t('services.ServiceCart.importFromEPGU') }}
            </q-tooltip>
          </q-btn>
          <q-icon
            size="22px"
            color="grey-9"
            :name="icons.epguImport"
            v-if="cardModel.epguImport"
          >
            <q-tooltip :delay="500">
              {{ $t('services.ServiceCart.epguImport') }}
            </q-tooltip>
          </q-icon>

          <q-btn
            :loading="signature.verificationLoading"
            @click="showSignModal({ mode: 'info', show: true })"
            v-if="cardModel.signature"
            round
            flat
            :color="signatureValidityColor"
          >
            <q-icon :name="icons.signature">
              <q-tooltip :delay="500">
                {{ $t('services.ServiceCart.checkSignature') }}
              </q-tooltip>
            </q-icon>
          </q-btn>
        </div>

        <div>
          <div class="gt-xs" v-if="canEdit">
            <q-btn
              v-if="
                !cardModel.settingsId &&
                $AC.haveScope(USER_SCOPES.SOCIAL_SETTINGS_GENERAL_ADMIN)
              "
              icon="settings"
              color="primary"
              class="q-mr-md"
              outline
              type="button"
              @click="openDialogSettings"
            >
              <q-tooltip :delay="500">
                {{ $t('services.ServiceCart.createSettings') }}
              </q-tooltip>
            </q-btn>
            <q-btn
              v-if="nexusTransfer.buttonFlag"
              icon="download"
              color="primary"
              outline
              class="q-mr-md"
              @click="nexusTransfer.exportNexusDialog = true"
            >
              <q-tooltip :delay="500"> Экспорт из Nexus </q-tooltip>
            </q-btn>
            <q-btn
              @click="saveService"
              v-if="cardModel.state === 'inProgress'"
              :loading="editLoading"
              color="primary"
              class="q-mr-md"
              outline
              type="button"
              icon="save"
            >
              <q-tooltip :delay="500">
                {{ $t('base.actions.save') }}
              </q-tooltip>
            </q-btn>
            <q-btn
              @click="dialogFixVersion = true"
              v-if="cardModel.state === 'inProgress'"
              :loading="editLoading"
              color="primary"
              class="q-mr-md"
              outline
              type="button"
              icon="lock"
            >
              <q-tooltip :delay="500">
                {{ $t('services.ServiceCart.fixVersion') }}
              </q-tooltip>
            </q-btn>

            <q-btn
              @click="goTo('inProgress')"
              v-if="cardModel.state === 'draft'"
              :loading="editLoading"
              color="primary"
              class="q-mr-md"
              label="Взять в работу"
              type="button"
              icon="how_to_reg"
            />
            <q-btn
              @click="goTo('readyToPublish')"
              v-if="cardModel.state === 'inProgress'"
              :loading="editLoading"
              color="primary"
              class="q-mr-md"
              label="Завершить"
              type="button"
            />
            <q-btn
              @click="showSignModal({ mode: 'sign', show: true })"
              :loading="signLoading"
              v-if="cardModel.state === 'readyToPublish'"
              color="primary"
              class="q-mr-md"
              :label="$t('services.ServiceCart.sign')"
              type="button"
              icon="gesture"
            />

            <q-btn
              @click="publishServiceDialog"
              v-if="
                cardModel.state === 'signed' ||
                cardModel.state === 'readyToPublish'
              "
              :loading="editLoading"
              color="primary"
              class="q-mr-md"
              label="Опубликовать"
              type="button"
              icon="cloud_upload"
            />
            <q-btn
              @click="goTo('inProgress')"
              v-if="
                cardModel.state === 'readyToPublish' ||
                cardModel.state === 'signed' ||
                cardModel.state === 'published'
              "
              :loading="editLoading"
              color="primary"
              class="q-mr-md"
              label="Редактировать"
              type="button"
              icon="create"
            />
            <q-btn
              @click="dialogDeleteConfim = true"
              v-if="cardModel.state === 'draft'"
              :loading="editLoading"
              color="negative"
              icon="delete_forever"
              class="q-mr-md"
              :label="$t('services.ServiceCart.delete')"
              type="button"
            />
            <q-btn
              color="negative"
              icon="report_problem"
              class="q-mr-md"
              @click="dialogImportConfim = true"
              type="button"
              :label="$t('services.ServiceCart.importService')"
            />
            <q-btn
              color="white"
              text-color="primary"
              class="q-mr-md"
              outline
              @click="dialogJsonEditor = true"
              type="button"
              icon="settings_ethernet"
            >
              <q-tooltip :delay="500">
                {{ $t('services.ServiceCart.jsonEditor') }}
              </q-tooltip>
            </q-btn>

            <!--  <q-btn disable unelevated color="primary" label="Установить" type="button" /> -->
          </div>

          <div>
            <SelectUsers
              v-model="usersCanEdit"
              :selected="card.updatePermission"
              @input="setUsersCanEdit"
            />
          </div>
        </div>
      </div>

      <div class="q-mx-md">
        <div class="q-py-md q-px-lg">
          <base-label-value class="q-pa-xs">
            <template v-slot:label>
              {{ $t('services.ServiceCart.fullName') }}
            </template>

            <template v-slot:value>
              {{ cardModel.fullName }}
            </template>
          </base-label-value>
          <base-label-value
            class="q-pa-xs service-base-label"
            v-if="stateColorMap"
          >
            <template v-slot:label>
              {{ $t('services.ServiceCart.state') }}
            </template>

            <template v-slot:value>
              <q-chip
                square
                :color="stateColorMap[cardModel.state]"
                size="md"
                dense
                text-color="white"
              >
                {{
                  cardModel.state
                    ? $t(`services.ServiceCart.${cardModel.state}`)
                    : 'В работе'
                }}
              </q-chip>
            </template>
          </base-label-value>
          <base-label-value
            class="q-pa-xs service-base-label"
            v-if="cardModel.state === 'published' && origin"
          >
            <template v-slot:label>
              {{ $t('services.ServiceCart.package') }}
            </template>

            <template v-slot:value>
              <q-btn
                type="a"
                target="_blank"
                :href="`${origin}/service/registry/service/backup/export/${cardModel.id}/zip`"
                icon="arrow_downward"
                color="white"
                text-color="primary"
              >
                <q-tooltip :delay="500"> Скачать</q-tooltip>
              </q-btn>
            </template>
          </base-label-value>
          <base-label-value class="q-pa-xs service-base-label">
            <template v-slot:label>
              {{ $t('services.ServiceCart.baseImport') }}
            </template>

            <template v-slot:value>
              {{ $t('services.ServiceCart.off') }}
              <q-toggle
                :disable="!cardModel || cardModel.state !== 'inProgress'"
                :value="baseImport"
                @input="onBaseImportChange"
                color="primary"
              />
              {{ $t('services.ServiceCart.on') }}
            </template>
          </base-label-value>
          <base-label-value class="q-pa-xs service-base-label">
            <template v-slot:label>
              Дополнительные настройки (проактив, выплаты)
            </template>
            <template v-slot:value>
              {{ $t('base.no') }}
              <q-toggle
                disable
                :value="!!card.settingsId"
                @input="onBaseImportChange"
                color="primary"
              />
              {{ $t('base.yes') }}
              <q-btn
                v-if="card.settingsId"
                text-color="primary"
                color="white"
                @click="goToAddSettings"
              >
                Перейти->
              </q-btn>
            </template>
          </base-label-value>
          <base-label-value class="q-pa-xs service-base-label">
            <template v-slot:label>
              {{ $t('services.ServiceCart.preorder') }}
            </template>

            <template v-slot:value>
              {{ $t('services.ServiceCart.off') }}
              <q-checkbox 
                v-model="cardModel.preorder"
                color="primary"
                @input="onPreorderChange"
              />
              {{ $t('services.ServiceCart.on') }}
            </template>
          </base-label-value>


          <base-label-value
            v-if="card.version"
            class="q-pa-xs service-base-label"
          >
            <template v-slot:label>
              {{ $t('base.version') }}
            </template>
            <template v-slot:value>
              {{ card.version }}
            </template>
          </base-label-value>
          <q-dialog v-model="baseImportDialog" persistent>
            <q-card class="q-pa-lg">
              <q-card-section>
                {{ $t('services.ServiceCart.baseImportOperationWarning') }}
              </q-card-section>
              <q-card-actions align="right">
                <q-btn outline color="primary" @click="deleteBaseImport">
                  {{ $t('services.ServiceCart.deleteBaseImport') }}
                </q-btn>
                <q-btn
                  @click="
                    baseImportDialog = false;
                    baseImport = true;
                  "
                  outline
                  color="primary"
                >
                  {{ $t('services.ServiceCart.cancel') }}
                </q-btn>
              </q-card-actions>
            </q-card>
          </q-dialog>
        </div>
      </div>
      <q-dialog class="full-width" v-model="dialogJsonEditor">
        <q-card class="no-shadow full-width">
          <q-card-section>
            <div class="text-h6">
              {{ $t('services.ServiceCart.jsonEditor') }}
            </div>
          </q-card-section>

          <q-card-section class="q-pt-none">
            <v-json-editor
              v-model="cardJson"
              ref="jsoneditor"
              @error="onJsonError"
              :options="{ mode: 'view', onValidate: onChangeJson }"
              height="400px"
            />
          </q-card-section>

          <!--  <q-card-actions align="right">
            <q-btn
              @click="saveNewCard"
              :disable="jsonError"
              color="primary"
              label="Применить"
            />

            <q-btn
              color="white"
              text-color="primary"
              @click="closeJsonEditor()"
              outline
              label="Отменить"
            />
          </q-card-actions> -->
        </q-card>
      </q-dialog>
      <q-dialog class="full-width" v-model="dialogDeleteConfim">
        <q-card class="no-shadow full-width">
          <q-card-section>
            <div class="text-h6">
              {{ $t('services.ServiceCart.confirmationMessage') }}
            </div>
          </q-card-section>

          <q-card-actions align="right">
            <q-btn @click="deleteService" color="primary" label="Удалить" />

            <q-btn
              color="white"
              text-color="primary"
              outline
              @click="dialogDeleteConfim = false"
              label="Отменить"
            />
          </q-card-actions>
        </q-card>
      </q-dialog>
      <q-dialog
        @hide="fixVersionDesc = ''"
        class="full-width"
        v-model="dialogFixVersion"
      >
        <q-card class="no-shadow full-width">
          <q-card-section>
            <div class="text-h6">
              {{ $t('services.ServiceCart.fixVersion') }}
            </div>
          </q-card-section>
          <q-card-section>
            <div>
              {{ $t('services.ServiceCart.versionToFix') }}
              <b>{{ card.version }}</b>
            </div>
          </q-card-section>
          <q-card-section>
            <q-input
              :label="$t('services.ServiceCart.releaseInfo')"
              v-model="fixVersionDesc"
              filled
              type="textarea"
            />
          </q-card-section>
          <q-card-section>
            <div>
              <q-checkbox
                v-model="isGlobalChange"
                :label="$t('services.ServiceCart.globalChange')"
              />
            </div>
            <div>
              <q-checkbox
                v-model="shouldIncludeDecisionsRegister"
                :label="$t('services.ServiceCart.includingDecisionsRegister')"
              />
            </div>
          </q-card-section>
          <q-card-actions align="right">
            <q-btn
              @click="fixVersion"
              color="primary"
              :label="$t('services.ServiceCart.fix')"
            />

            <q-btn
              color="white"
              text-color="primary"
              outline
              @click="dialogFixVersion = false"
              :label="$t('base.actions.cancel')"
            />
          </q-card-actions>
        </q-card>
      </q-dialog>
      <q-dialog class="full-width" v-model="saveConflict">
        <q-card class="no-shadow full-width">
          <q-card-section>
            <div class="text-h6">
              Внимание, объект был отредактирован другим пользователем.
              Продолжить сохранение?
            </div>
          </q-card-section>

          <q-card-actions align="right">
            <q-btn
              @click="forceSaveService"
              color="primary"
              label="Сохранить"
            />
            <q-btn
              color="white"
              text-color="primary"
              outline
              @click="saveConflict = false"
              label="Отменить"
            />
          </q-card-actions>
        </q-card>
      </q-dialog>
      <q-dialog
        @hide="exitSubmitVersion"
        class="full-width"
        v-model="dialogPublishConfim"
      >
        <q-card class="no-shadow full-width">
          <q-card-section>
            <div class="text-h6">
              {{ $t('services.ServiceCart.publishConfirmationMessage') }}
            </div>
          </q-card-section>
          <q-card-section>
            <q-select
              v-model="publishVersion"
              :options="adoptedPublishVersions"
              :loading="versionsLoading"
              label="Выбор версии"
            />
          </q-card-section>
          <q-card-section>
            <q-input
              :label="$t('services.ServiceCart.releaseInfo')"
              :value="changelog"
              filled
              readonly
              type="textarea"
            />
          </q-card-section>

          <q-card-actions align="right">
            <q-btn
              @click="submitVersion"
              color="primary"
              label="Опубликовать"
            />

            <q-btn
              color="white"
              text-color="primary"
              outline
              @click="dialogPublishConfim = false"
              label="Отменить"
            />
          </q-card-actions>
        </q-card>
      </q-dialog>
      <q-dialog class="full-width" v-model="dialogImportConfim" persistent>
        <q-card class="no-shadow full-width">
          <q-card-section>
            <div class="text-h6">
              {{ $t('services.ServiceCart.confirmationImport') }}
            </div>
          </q-card-section>

          <q-card-actions align="right">
            <q-btn
              @click="importService"
              color="primary"
              :label="$t('services.ServiceCart.importService')"
            />

            <q-btn
              color="white"
              text-color="primary"
              outline
              @click="dialogImportConfim = false"
              :label="$t('services.ServiceCart.cancel')"
            />
          </q-card-actions>
          <q-inner-loading :showing="importStart">
            <q-spinner-gears size="50px" color="primary" />
          </q-inner-loading>
        </q-card>
      </q-dialog>
      <q-dialog
        class="full-width"
        v-model="nexusTransfer.exportNexusDialog"
        persistent
      >
        <q-card>
          <q-card-section>
            <span class="text-h6">Экспорт услуги из Nexus</span>
          </q-card-section>
          <q-card-section>
            <q-select
              v-model="nexusTransfer.selectedVersion"
              :options="nexusTransfer.serviceVersions"
              label="Выберите версию"
            />
          </q-card-section>
          <q-card-actions align="right">
            <q-btn
              label="Экспорт"
              outline
              @click="exportFromNexus"
              :disable="!nexusTransfer.selectedVersion"
            />
            <q-btn
              label="Отмена"
              outline
              @click="nexusTransfer.exportNexusDialog = false"
            />
          </q-card-actions>
        </q-card>
      </q-dialog>
      <settings-dialog
        ref="dialogSettings"
        :cardModel="cardModel"
        @init="init"
      />
      <Ecp
        @save-service="saveService"
        v-model="signature.dialog.show"
        :serviceID="common && common.id"
        :signatureData.sync="signature"
        :signLoading.sync="signLoading"
        :signature="cardModel && cardModel.signature"
        :cert="cardModel && cardModel.cert"
        @inject-signature="injectSignature"
      />
    </q-card>
    <base-tabs :currentTab="tabs.current" v-if="!loading" :tabs="tabs.list" />
    <q-inner-loading :showing="loading">
      <q-spinner-gears color="primary" size="50px" />
    </q-inner-loading>
  </div>
</template>

<script lang="ts">
// @ts-nocheck
// @ts-ignore
import ReturnToParentView from '@mixins/ReturnToParentView';
// @ts-ignore
import VJsonEditor from 'v-jsoneditor';
import { updateRejects } from '@utils/update-rejects';
import { updateService } from '@services/registry-service';
import { ServiceApi } from '@openapi/registry-service';
import get from 'lodash/get';
import isEqual from 'lodash/isEqual';
import { WorkflowServiceApi } from '@openapi/wf';
import { ComponentApi } from '@openapi/nexus-transfer';
import { notifyError, notifySuccess } from '@utils/notify';
import Ecp from '@components/cards/services/Ecp.vue';
import SettingsDialog from '@components/cards/services/SettingsDialog.vue';
import SelectUsers from './components/select-users.vue';
import { USER_SCOPES } from '@constants/entities/Scope';
import { isEmpty } from 'lodash';
import { pushRoute } from '@utils/routes';

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

export default {
  name: 'services',
  components: {
    VJsonEditor,
    Ecp,
    SettingsDialog,
    SelectUsers,
  },
  props: ['common', 'model', 'user-task'],
  mixins: [ReturnToParentView],
  data() {
    return {
      USER_SCOPES: USER_SCOPES,
      baseImport: false,
      isGlobalChange: false,
      shouldIncludeDecisionsRegister: false,
      baseImportDialog: false,
      cardModel: null,
      editLoading: false,
      signLoading: false,
      saveConflict: false,
      cardJson: [],
      modelDump: null,
      unsavedChanges: false,
      dialogJsonEditor: false,
      dialogDeleteConfim: false,
      dialogPublishConfim: false,
      dialogImportConfim: false,
      dialogFixVersion: false,
      fixVersionDesc: '',
      importStart: false,
      publishVersion: '',
      publishVersions: [],
      versionsLoading: false,
      petitionType: '',
      numberPrefix: '',
      jsonError: false,
      state: 'inProgress',
      importProcessKey: 'ZipServiceImportProcess',
      fixVersionProcessKey: 'ZipServiceExportToNexusProcess',
      fetchVersionsProcessKey: 'VersionFixationProcess',
      isVersionFixationSubmitted: false,
      fetchVersionsProcessTraceId: null,
      fetchVersionTask: {},
      processTimeouts: [],
      type: '',
      versionInfo: {},
      tabs: {
        current: this.common.active,
        list: [],
      },
      icons: {
        signature: 'gesture',
        kcrImport: 'verified_user',
        epguImport: 'assignment_returned',
      },
      // todo статусы
      states: [
        {
          label: 'Черновик',
          value: 'draft',
        },
        {
          label: 'В работе',
          value: 'inProgress',
        },
        {
          label: 'Готова к подписанию',
          value: 'readyToPublish',
        },
        {
          label: 'Подписана',
          value: 'signed',
        },
        {
          label: 'Опубликована',
          value: 'published',
        },
      ],
      // Костыль на время, пока не добавят новые коллекции для кцр на registry-service
      fakeLinks: ['healthStatus', 'scope', 'legalActs'],
      signature: {
        certificate: null,
        certificates: null,
        dialog: {
          type: '',
          show: false,
        },
        verificationLoading: false,
        isSignatureValid: null,
        error: null,
      },
      usersCanEdit: [],
      nexusTransfer: {
        buttonFlag: true,
        selectedVersion: null,
        exportNexusDialog: false,
        serviceVersions: [],
      },
    };
  },
  beforeDestroy() {
    this.processTimeouts.forEach((timeout) => {
      clearTimeout(timeout);
    });
  },
  computed: {
    changelog() {
      const changelog = get(this, 'versionInfo.notes', null);
      if (!changelog) return '';
      return JSON.stringify(changelog, null, 2);
    },
    adoptedPublishVersions() {
      return Object.values(this.publishVersions).map((version) => {
        return {
          label: version,
          value: version,
        };
      });
    },
    adoptedPublishVersion() {
      return this.publishVersions[this.publishVersion.label];
    },
    signatureValidityColor() {
      if (!get(this.cardModel, 'signature')) {
        return 'warning';
      }

      const valid = get(this.signature, 'isSignatureValid');

      if (valid === null) {
        return 'info';
      }

      return valid ? 'positive' : 'negative';
    },
    origin() {
      return typeof window !== 'undefined' ? window.location.origin : '';
    },

    loading() {
      return (
        this.$store.getters['registryService/services/servicesLoading'] || false
      );
    },

    card() {
      return (
        this.$store.getters['registryService/services/servicesCard'] || null
      );
    },

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

    outputData() {
      return {
        fullName: this.fullName,
        shortName: this.shortName,
        petitionType: this.petitionType,
        numberPrefix: this.numberPrefix,
        type: this.type,
      };
    },

    title() {
      const title = this.shortName || this.$t('services.ServiceCart.title');

      if (!title) {
        return title;
      }

      return title[0].toUpperCase() + title.slice(1);
    },
    canEdit(): boolean {
      return this.$store.getters['registryService/services/canEdit'];
    },
  },
  mounted() {
    // Глушим кнопки на проде
    this.nexusTransfer.buttonFlag =
      window.location.host !== 'pgs2.gosuslugi.ru';
  },
  created() {
    this.init();
  },

  watch: {
    publishVersion: function (val) {
      if (!val.value) {
        this.versionInfo = {};
        return;
      }
      this.fetchVersionInfo();
    },
    'common.active': function (val) {
      this.tabs.current = val;
    },

    card: {
      handler: function (val, prevVal) {
        if (val) {
          if (
            (isEmpty(prevVal) && !isEmpty(val)) ||
            (!isEmpty(prevVal) && !isEmpty(val))
          ) {
            this.setInitialCanEdit();
          }

          this.cardModel = val;
          this.setCardJson(val);
          this.baseImport = !!val.useBaseImport;
          if (val.state) {
            this.state = val.state;
          }
        }
      },

      immediate: true,
    },
    cardModel: {
      handler: function (model) {
        this.unsavedChanges = model !== null && !isEqual(model, this.modelDump);
        this.$root.$emit('unsavedChanges', this.unsavedChanges);
      },
    },
  },

  methods: {
    updateBasicCardModelBaseImport(): void {
      const newCard = { ...this.card };
      newCard.useBaseImport = this.baseImport;
      this.$store.dispatch('registryService/services/setCardForJson', newCard);
    },
    onBaseImportChange(val: boolean): void {
      this.baseImport = val;
      if (!val) {
        this.baseImportDialog = true;
      } else {
        this.updateBasicCardModelBaseImport();
      }
    },
    onPreorderChange(val: boolean): void {
      this.cardModel.preorder = val;
      this.updateBasicCardModelBaseImport();
    },
    deleteBaseImport(): void {
      this.baseImport = false;
      this.baseImportDialog = false;
      this.updateBasicCardModelBaseImport();
    },
    init() {
      this.initResource();
      this.initTabsList();
    },
    initNexusTransfer() {
      ntApi
        .getServiceVersionsByServiceName(this.modelDump.name)
        .then((response) => {
          this.nexusTransfer.serviceVersions = response.data.assets.map((i) => {
            return {
              label: i.version,
              value: i.assetId,
            };
          });
        });
    },

    importFromXSD() {
      const serviceCode = get(this.cardModel, 'name') || this.common.id;

      const route = {
        path: '/services/modeler/create',
        query: {
          serviceRegistryID: get(this.common, 'id'),
          serviceLabel: get(this.cardModel, 'fullName'),
          from: window.location.href,
          serviceCode,
        },
      };

      this.$router.push(route);
    },

    async setCerts() {
      const certs = await this.$store
        .dispatch('utils/cryptoPro/fetchCertificates')
        .catch((error) => {
          console.error(
            '[service data card][init] Could not get certificates',
            error
          );

          return null;
        });

      const certsOptions = certs
        ? certs.map((cert) => ({
            label: cert.subjectName,
            value: cert,
          }))
        : null;

      this.$set(this.signature, 'certificates', certsOptions);
    },

    openDialogSettings() {
      this.$refs.dialogSettings.createSettings();
    },

    goTo(state) {
      /*
      Error: [vuex] do not mutate vuex store state outside mutation handlers.
      * */
      this.cardModel.state = state;
      this.saveService();
      this.$nextTick(() => this.$forceUpdate());
    },

    goToAddSettings(event) {
      pushRoute(
        this.$router,
        {
          name: 'cards',
          params: {
            id: this.card.settingsId,
            path: 'additional-settings',
          },
          query: {
            active: 'basic',
            components: this.$store.getters[
              'cardComponents/additionalSettings/components'
            ],
          },
        },
        event.shiftKey
      );
    },

    onJsonError() {
      this.jsonError = true;
    },

    setCardJson(val) {
      this.cardJson = val;
    },

    onChangeJson() {
      this.jsonError = false;
    },

    saveNewCard() {
      this.$store.dispatch(
        'registryService/services/setCardForJson',
        this.cardJson
      );
      this.dialogJsonEditor = false;
    },

    closeJsonEditor() {
      this.setCardJson(this.card);
      this.dialogJsonEditor = false;
    },
    goToServicesList() {
      if (
        !this.unsavedChanges ||
        (this.unsavedChanges &&
          window.confirm(
            'На странице есть несохраненные изменения. Продолжить?'
          ))
      ) {
        this.returnToParentView('/services');
      }
    },
    initTabsList() {
      this.tabs.list = [
        {
          name: this.$t('services.Basic.tab'),
          path: 'basic',
          visible: true,
        },
        {
          name: this.$t('services.ScreenFormsCard.tab'),
          path: 'forms',
          visible: true,
        },
        {
          name: this.$t('services.ProcessesCard.tab'),
          path: 'processes',
          visible: true,
        },
        {
          name: this.$t('services.VerificationsCard.tab'),
          path: 'verifications',
          visible: () =>
            get(this.cardModel, 'state') !== 'draft' ||
            !get(this.cardModel, 'kcrImport'),
        },
        {
          name: this.$t('services.DocumentsCard.tab'),
          path: 'documents',
          visible: true,
        },
        {
          name: this.$t('services.DirectoriesCard.tab'),
          path: 'directories',
          visible: () =>
            get(this.cardModel, 'state') !== 'draft' ||
            !get(this.cardModel, 'kcrImport'),
        },
        {
          name: this.$t('services.InterdepartmentalCard.tab'),
          path: 'interagencies',
          visible: true,
        },
        {
          name: this.$t('services.StagesCard.tab'),
          path: 'stages',
          visible: true,
        },
        {
          name: this.$t('services.Income.tab'),
          path: 'income',
          visible: () => !!get(this.cardModel, 'hasSDD'),
        },
        {
          name: this.$t('services.PaymentCard.tab'),
          path: 'payments',
          visible: true,
        },
        {
          name: this.$t('services.ModelCard.tab'),
          path: 'form_model',
          visible: () =>
            get(this.cardModel, 'state') !== 'draft' ||
            !get(this.cardModel, 'kcrImport'),
        },
        {
          name: this.$t('services.digitalRegulations.tab'),
          path: 'digital_regulations',
          visible: () => !!get(this.cardModel, 'kcrImport'),
        },
        {
          name: this.$t('services.export.tab'),
          path: 'export',
          visible: true,
        },
      ];
    },

    saveService() {
      this.editLoading = true;
      const serviceModel = { ...this.cardModel };
      Object.keys(serviceModel).forEach((key) => {
        if (
          Array.isArray(serviceModel[key]) &&
          !this.fakeLinks.some((i) => i === key)
        ) {
          serviceModel[key] = serviceModel[key].map((i) => i.id || i);
        }
      });

      updateRejects(this.cardModel)
        .catch((e) => {
          console.error(e);
          notifyError(e.message.toString());
        })
        .then(() => updateService(serviceModel))
        .then(({ data }) => {
          if (this.cardModel) {
            this.cardModel.modified = data.modified;
          }
          this.unsavedChanges = false;
          this.$store.commit('registryService/services/unsavedChanges', false);
          this.$root.$emit('unsavedChanges', this.unsavedChanges);
          notifySuccess(this.$t('services.ServiceCart.saveSuccess'));
        })
        .catch((e) => {
          this.saveServiceErrorHandler(e);
        })
        .finally(() => {
          this.editLoading = false;
          this.signLoading = false;

          if (get(this.cardModel, 'signature')) {
            this.$set(this.signature, 'unverified', true);
          }

          if (get(this.signature, 'dialog.show')) {
            this.showSignModal({ mode: null, show: false });
          }
        });
    },

    fixVersionErrorHandler() {
      this.$store.commit('registryService/services/servicesLoading', false);
      notifyError(this.$t('services.ServiceCart.fixError'));
    },
    publishErrorHandler() {
      this.$store.commit('registryService/services/servicesLoading', false);
      notifyError(this.$t('services.ServiceCart.publishError'));
    },
    saveServiceErrorHandler(e) {
      if (e.status && e.status === 409) {
        this.saveConflict = true;
      } else {
        notifyError(e.message.toString());
      }
    },

    async deleteService() {
      try {
        await serviceApi.deleteService([this.cardModel.id]);
        notifySuccess(this.$t('services.ServiceCart.deleteSuccess'));
        this.$router.push({
          path: `/services`,
        });
      } catch (e) {
        notifyError(e.message.toString());
      }
    },

    async initResource() {
      await this.$store.dispatch('registryService/services/getServiceMeta', {
        id: get(this.common, 'id'),
        opts: {
          noCommit: get(this.$route, 'params.noCommit', false),
          expand: [
            'interagencies.formRequest',
            'interagencies.formResponse',
            'interagencies.attachments',
            'documents.form',
            'formsExtra',
            'mapping',
          ],
        },
      });
      this.modelDump = this.card;
      this.unsavedChanges = this.$store.getters[
        'registryService/services/unsavedChanges'
      ];
      this.initNexusTransfer();
      this.$root.$emit('unsavedChanges', this.unsavedChanges);
    },

    showSignModal({ mode, show }) {
      this.$set(this.signature.dialog, 'mode', mode);
      this.$set(this.signature.dialog, 'show', show);

      if (!this.signature.certificates && mode === 'sign') {
        this.setCerts();
      }

      if (mode === 'info') {
        this.$set(this.signature, 'unverified', true);
      }
    },

    injectSignature(signatureData) {
      this.$set(this.cardModel, 'signature', signatureData.signature);
      this.$set(this.cardModel, 'cert', signatureData.cert);
      this.$set(this.cardModel, 'state', signatureData.state);
    },

    async forceSaveService() {
      const service = await this.$store.dispatch(
        'registryService/services/getServiceMeta',
        { id: get(this.common, 'id') }
      );
      this.saveConflict = false;
      this.cardModel.modified = service.modified;
      this.saveService();
    },
    async importService() {
      if (!get(this.cardModel, 'name')) {
        return;
      }

      this.importStart = true;

      try {
        const {
          data: { traceId },
        } = await wfApi.start({
          processKey: this.importProcessKey,
          data: {
            service: get(this.cardModel, 'name'),
          },
        });

        const timeout = setTimeout(() => {
          notifyError(this.$t('services.ServiceCart.importError'));
          this.importStart = false;
          this.dialogImportConfim = false;
        }, 300000);
        this.processTimeouts.push(timeout);

        const handler = (e: any) => {
          const data = JSON.parse(get(e, 'data', '{}'));
          if (data.traceId === traceId) {
            clearTimeout(timeout);
            const timeoutIndex = this.processTimeouts.indexOf(timeout);
            if (timeoutIndex !== -1)
              this.processTimeouts.splice(timeoutIndex, 1);
            this.importStart = false;
            this.dialogImportConfim = false;
            this.$websockets.removeListener(handler);
          }
        };

        this.$websockets.addListener(handler);

        notifySuccess(this.$t('services.ServiceCart.importSuccess'));
      } catch (e) {
        notifyError(e.message.toString());
      }
    },
    closeProcess(taskId: string): void {
      wfApi.submitForm(taskId, {});
    },
    async fixVersion(): void {
      if (!this.fixVersionDesc) {
        notifyError('Заполните информацию о релизе');
        return;
      }
      try {
        this.$store.commit('registryService/services/servicesLoading', true);
        const {
          data: { traceId },
        } = await wfApi.start({
          processKey: this.fixVersionProcessKey,
          userId: this.$store.getters['oidcClient/currentUser'].sub,
          data: {
            service: get(this.cardModel, 'name'),
            isRelease: this.isGlobalChange,
            comment: this.fixVersionDesc,
            withRegistry: this.shouldIncludeDecisionsRegister,
          },
        });
        const timeout = setTimeout(
          this.fixVersionErrorHandler.bind(this),
          300000
        );
        this.processTimeouts.push(timeout);
        const handler = (e: any) => {
          const data = JSON.parse(get(e, 'data', '{}'));
          if (data.traceId === traceId) {
            this.$websockets.removeListener(handler);
            clearTimeout(timeout);
            const timeoutIndex = this.processTimeouts.indexOf(timeout);
            if (timeoutIndex !== -1)
              this.processTimeouts.splice(timeoutIndex, 1);
            const isSuccess = data?.body?.userTask?.outData?.success;
            if (isSuccess) {
              notifySuccess('Версия зафиксирована');
            }
            if (isSuccess === false) {
              this.fixVersionErrorHandler();
            }
            this.closeProcess(data?.body?.userTask?.taskId);
            this.$store.commit(
              'registryService/services/servicesLoading',
              false
            );
          }
        };

        this.$websockets.addListener(handler);
        notifySuccess(this.$t('services.ServiceCart.fixStarted'));
        this.fixVersionDesc = '';
        this.dialogFixVersion = false;
      } catch (e) {
        notifyError(e.message.toString());
      }
    },
    fetchVersionsErrorHandler(): void {
      this.versionsLoading = false;
      notifyError('Не удалось загрузить версии');
    },
    async fetchVersions() {
      try {
        this.versionsLoading = true;
        const { data: result } = await wfApi.start({
          processKey: this.fetchVersionsProcessKey,
          userId: this.$store.getters['oidcClient/currentUser'].sub,
          data: {
            serviceName: get(this.cardModel, 'name'),
          },
        });
        this.fetchVersionsProcessTraceId = result.traceId;
        const timeout = setTimeout(
          this.fetchVersionsErrorHandler.bind(this),
          300000
        );
        this.processTimeouts.push(timeout);
        const handler = (e: any) => {
          const data = JSON.parse(get(e, 'data', '{}'));
          if (data.traceId === this.fetchVersionsProcessTraceId) {
            this.publishVersions =
              data?.body?.userTask?.outData?.avaliableVersions || [];
            const isSuccess = data?.body?.userTask?.outData?.success;
            if (isSuccess === false) {
              notifyError(data?.body?.userTask?.outData?.text);
            }
            if (data.body?.type === 'task') {
              this.fetchVersionTask = data?.body?.userTask || {};
              this.versionsLoading = false;
              this.$websockets.removeListener(handler);
              clearTimeout(timeout);
              const timeoutIndex = this.processTimeouts.indexOf(timeout);
              if (timeoutIndex !== -1)
                this.processTimeouts.splice(timeoutIndex, 1);
            }
          }
        };

        this.$websockets.addListener(handler);
      } catch (e) {
        notifyError(e.message.toString());
      }
    },
    publishServiceDialog(): void {
      this.fetchVersions();
      this.dialogPublishConfim = true;
    },
    exitSubmitVersion(): void {
      if (!this.isVersionFixationSubmitted) {
        try {
          wfApi.submitForm(this.fetchVersionTask?.taskId, {
            action: 'exit',
          });
        } catch (e) {
          console.error(e.message);
        }
      }
      this.publishVersion = '';
      this.isVersionFixationSubmitted = false;
      this.dialogPublishConfim = false;
    },
    validateSubmitVersionInfo() {
      if (!this.publishVersion.label) {
        notifyError('Выберите версию');
        return false;
      }
      return true;
    },
    async fetchVersionInfo() {
      try {
        await wfApi.submitForm(this.fetchVersionTask?.taskId, {
          selected: this.publishVersion.value,
          action: 'getChangelog',
        });
        const handler = (e: any) => {
          const data = JSON.parse(get(e, 'data', '{}'));
          if (data.traceId === this.fetchVersionsProcessTraceId) {
            this.versionInfo = data?.body?.userTask?.outData?.changelog || {};

            if (data.body?.type === 'task') {
              this.fetchVersionTask = data?.body?.userTask || {};
              this.$websockets.removeListener(handler);
            }
          }
        };
        this.$websockets.addListener(handler);
      } catch (e) {
        notifyError(e.message.toString());
      }
    },
    async submitVersion() {
      const isValid = this.validateSubmitVersionInfo();
      if (!isValid) return;
      this.isVersionFixationSubmitted = true;
      try {
        this.$store.commit('registryService/services/servicesLoading', true);

        await wfApi.submitForm(this.fetchVersionTask?.taskId, {
          selected: this.publishVersion.value,
          action: 'do',
        });
        const handler = (e: any) => {
          const data = JSON.parse(get(e, 'data', '{}'));
          if (data.traceId === this.fetchVersionsProcessTraceId) {
            const isSuccess = data?.body?.userTask?.outData?.success;
            if (isSuccess) {
              this.submitVersionSuccess();
            }
            if (isSuccess === false) {
              this.submitVersionError();
            }
            this.$websockets.removeListener(handler);
            this.$store.commit(
              'registryService/services/servicesLoading',
              false
            );
            this.publishVersion = '';
            this.dialogPublishConfim = false;
            this.isVersionFixationSubmitted = false;
          }
        };
        notifySuccess('Процесс переноса версии запущен');

        this.$websockets.addListener(handler);
      } catch (e) {
        notifyError(e.message.toString());
      }
    },
    submitVersionSuccess(): void {
      notifySuccess('Версия перенесена в релизный репозиторий');
      this.cardModel.state = 'published';
    },
    submitVersionError(): void {
      notifyError('Не удалось перенести версию в релизный репозиторий');
    },
    setUsersCanEdit(users) {
      const userIds = users.length ? users.map((u) => u.id) : null;
      const newCard = { ...this.card, updatePermission: userIds };
      this.$store.dispatch('registryService/services/setCardForJson', newCard);
    },
    setInitialCanEdit() {
      const canEdit =
        !this.card.updatePermission ||
        this.$AC.haveScope(USER_SCOPES.MAIN_SERVICE_ADMIN) ||
        (this.$AC.haveScope(USER_SCOPES.SERVICES_CONSTRUCT) &&
          this.card.updatePermission?.length &&
          this.card.updatePermission.includes(
            this.$store.getters['oidcClient/currentUser'].sub
          ));
      this.$store.commit('registryService/services/setCanEdit', canEdit);
    },
    exportFromNexus() {
      ntApi
        .downloadAssetById(this.nexusTransfer.selectedVersion.value, {
          responseType: 'blob',
        })
        .then((response) => {
          // fixme: сделать общую функцию сохранения
          const blob = new Blob([response.data]);
          const link = document.createElement('a');
          link.href = URL.createObjectURL(blob);
          const fileName = response.headers['content-disposition']
            .split(';')[1]
            .replace('filename=', '');
          link.download = `${fileName}.zip`;
          link.click();
          URL.revokeObjectURL(link.href);
          this.nexusTransfer.exportNexusDialog = false;
        });
    },
  },
};
</script>

<style scoped lang="sass">
.service-base-label
  height: 37px
  min-height: 37px
  display: flex
  align-items: center !important
</style>
