<i18n>
    {
    "en": {
        "ecp": {
            "checkSignature": "Check signature",
            "viewSignature": "Signature (EDS)",
            "viewSignatureText": "Check",
            "documentSignature": "Document signature",
            "signatureIsValid": "Signature is valid",
            "signatureIsInvalid": "Signature is invalid",
            "signed": "Signed",
            "certificatePublisher": "Certificate publisher",
            "document": "Document",
            "download": "Download",
            "signedFile": "Signed file",
            "certificate": "Certificate",
            "sign": "Sign",
            "cancel": "Cancel",
            "noCertSelected": "Необходимо выбрать сертификат",
            "signatureIsBeingVerified": "Checking validity of the signature",
            "validTo": "Valid to"
        }
    },
    "ru": {
        "ecp": {
            "checkSignature": "Проверить подпись",
            "viewSignature": "Подпись (ЭЦП)",
            "viewSignatureText": "Проверить",
            "documentSignature": "Подпись документа",
            "signatureIsValid": "Подпись достоверна",
            "signatureIsInvalid": "Подпись недостоверна",
            "signed": "Подписана",
            "certificatePublisher": "Издатель сертификата",
            "document": "Документ",
            "download": "Скачать",
            "signedFile": "Файл с подписью",
            "certificate": "Сертификат",
            "sign": "Подписать",
            "cancel": "Отмена",
            "noCertSelected": "Необходимо выбрать сертификат",
            "signatureIsBeingVerified": "Проверяем достоверность подписи",
            "validTo": "Действителен до"
        }
    }
}
</i18n>
<template>
  <q-dialog
    class="full-width"
    :value="signatureData.dialog.show"
    @hide="hideModal"
  >
    <q-card class="full-width no-shadow" style="max-width: 480px">
      <q-card-section>
        <div class="text-h6">
          {{ $t('ecp.documentSignature') }}
        </div>
      </q-card-section>
      <template v-if="signatureData.dialog.mode === 'sign'">
        <q-card-section class="q-gutter-y-md">
          <q-select
            ref="certSelect"
            :loading="!signatureData.certificates"
            :label="$t('ecp.certificate')"
            :value="signatureData.certificate"
            :options="signatureData.certificates"
            hide-bottom-space
            :rules="[signatureData.certificate || $t('ecp.noCertSelected')]"
            outlined
            @input="
              $emit(
                'update:signatureData',
                Object.assign(signatureData, { certificate: $event })
              )
            "
          >
            <template #option="{ opt, toggleOption, selected }">
              <q-item
                v-if="opt && opt.value"
                :class="{
                  'bg-red-1': isExpired(opt.value.validTo),
                  'bg-blue-1': selected,
                }"
                clickable
                @click="toggleOption(opt)"
              >
                <div>
                  <div class="text-grey-8">{{ opt.label }}</div>
                  <div :style="{ fontSize: '0.75rem' }" class="">
                    {{ $t('ecp.validTo') }}:
                    {{ convertDateFromBackendFormat(opt.value.validTo) }}
                  </div>
                </div>
              </q-item>
            </template>
          </q-select>
        </q-card-section>
        <q-card-actions align="right">
          <q-btn
            unelevated
            color="negative"
            :label="$t('ecp.cancel')"
            @click="hideModal"
          />
          <q-btn
            :disable="!signatureData.certificate"
            unelevated
            color="primary"
            :label="$t('ecp.sign')"
            :loading="signLoading"
            @click="signService"
          />
        </q-card-actions>
      </template>
      <template v-if="signatureData.dialog.mode === 'info'">
        <q-card-section class="q-gutter-y-md">
          <q-banner class="bg-grey-1">
            <template #avatar>
              <q-icon
                v-if="signatureData.isSignatureValid"
                color="positive"
                name="check_circle_outline"
              />
              <q-icon
                v-else-if="signatureData.isSignatureValid === false"
                color="negative"
                name="error"
              />
              <q-spinner-gears v-else color="primary" size="50px" />
            </template>
            <div v-if="signatureData.isSignatureValid">
              {{ $t('ecp.signatureIsValid') }}
            </div>
            <div v-else-if="signatureData.isSignatureValid === false">
              {{ $t('ecp.signatureIsInvalid') }}
            </div>
            <div v-else>
              {{ $t('ecp.signatureIsBeingVerified') }}
            </div>
          </q-banner>
          <table v-if="cert" class="text-primary">
            <tr>
              <td>
                <q-item>
                  <q-item-section>
                    <q-item-label class="text-grey-9">
                      {{ $t('ecp.signed') }}
                    </q-item-label>
                  </q-item-section>
                </q-item>
              </td>
              <td>
                <q-item>
                  <q-item-section>
                    <q-item-label>
                      {{ get(cert, 'subjectName') }}
                    </q-item-label>
                  </q-item-section>
                </q-item>
              </td>
            </tr>
            <tr>
              <td>
                <q-item>
                  <q-item-section>
                    <q-item-label class="text-grey-9">
                      {{ $t('ecp.certificatePublisher') }}
                    </q-item-label>
                  </q-item-section>
                </q-item>
              </td>
              <td>
                <q-item>
                  <q-item-section>
                    <q-item-label>
                      {{ get(cert, 'issuerName') }}
                    </q-item-label>
                  </q-item-section>
                </q-item>
              </td>
            </tr>
          </table>
        </q-card-section>
      </template>
    </q-card>
  </q-dialog>
</template>

<script lang="ts">
// @ts-nocheck
import { convertDateFromBackendFormat, isPastDate } from '@utils/format-date';
import cloneDeep from 'lodash/cloneDeep';
import get from 'lodash/get';

export default {
  name: 'Ecp',

  props: ['signatureData', 'serviceID', 'signature', 'signLoading', 'cert'],

  data() {
    return {};
  },

  watch: {
    'signatureData.unverified': {
      handler(unverified) {
        if (unverified) {
          this.verifySignature();
        }
      },
      immediate: true,
    },
  },

  methods: {
    get,
    isExpired(date) {
      return isPastDate(date);
    },
    hideModal() {
      this.$emit(
        'update:signatureData',
        Object.assign({}, this.signatureData, {
          dialog: { show: false, mode: null },
          unverified: false,
        })
      );
    },
    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;

      const updated = cloneDeep(this.signature);

      this.$set(updated, 'certificates', certsOptions);

      this.$emit('update:signature', updated);
    },

    async getBareServiceHash() {
      const bareService = await this.$store
        .dispatch('registryService/services/getServiceMeta', {
          id: this.serviceID,
          opts: {
            noExpand: true,
            noCommit: true,
          },
        })
        .catch((error) => {
          console.error(
            '[service data card][get bare service hash] could not get service data',
            error
          );

          return null;
        });

      if (!bareService) {
        return null;
      }

      delete bareService.signature;
      delete bareService.modified;
      delete bareService.state;
      delete bareService.cert;

      const serviceBlob = new Blob([JSON.stringify(bareService)], {
        type: 'application/json',
      });

      return await this.$store.dispatch('utils/cryptoPro/generateHash', {
        file: serviceBlob,
      });
    },

    async signService() {
      this.$emit('update:signLoading', true);

      const cert = this.signatureData.certificate;

      if (!cert) {
        console.error(
          '[service data card][sign service] no cert available, bailing',
          {
            cert,
            signature: this.signatureData,
          }
        );

        this.$emit('update:signLoading', false);

        return;
      }

      const hash = await this.getBareServiceHash();

      const signature = await this.$store.dispatch(
        'utils/cryptoPro/createSignature',
        {
          hash,
          certificate: cert.value,
        }
      );

      this.$emit('inject-signature', {
        signature,
        cert: cert.value,
        state: 'signed',
      });
      this.$emit('save-service');
    },

    async verifySignature() {
      const signatureData = cloneDeep(this.signatureData);

      this.$set(signatureData, 'verificationLoading', true);
      this.$emit('update:signatureData', signatureData);

      const signature = this.signature;

      if (!signature) {
        console.error('[service data card][verify signature] no signature', {
          signature,
        });

        return;
      }

      const hash = await this.getBareServiceHash().catch((error) => {
        console.error(
          '[service data card][verify signature] hash generation error',
          error,
          { signature }
        );

        this.$set(signatureData, 'verificationLoading', false);
        this.$set(signatureData, 'unverified', false);
        this.$set(signatureData.dialog, 'show', false);
        this.$set(signatureData.dialog, 'mode', null);

        this.$emit('update:signatureData', signatureData);
      });

      const valid = await this.$store
        .dispatch('utils/cryptoPro/verifySignature', {
          hash,
          signature,
        })
        .catch((error) => {
          console.error('[ecp][verify signature] ', error);
          return false;
        });

      this.$set(signatureData, 'isSignatureValid', valid);
      this.$set(signatureData, 'verificationLoading', false);
      this.$set(signatureData, 'unverified', false);

      this.$emit('update:signatureData', signatureData);
    },
    convertDateFromBackendFormat,
  },
};
</script>
