<i18n>
{
  "en": {
    "ResponseCard": {
      "responseXML": "Response.xml",
      "tab": "Response parameters",
      "noChecksResult": "No results for the response data",
      "noFile": "File not found",
      "downloadXML": "Download xml",
      "downloadApplication": "Download application",
      "ApplicationsTitle": "Applications"
    }
  },
  "ru": {
    "ResponseCard": {
      "responseXML": "Ответ.xml",
      "tab": "Данные ответа",
      "noChecksResult": "Нет результатов по данным ответа",
      "noFile": "Файл не найден",
      "downloadXML": "Скачать xml",
       "ApplicationsTitle": "Список вложений",
      "downloadApplication": "Скачать вложение"
    }
  }
}
</i18n>

<template>
  <div v-if="common.active === 'response' && !loading" class="q-pb-md">
    <q-card class="no-shadow q-gutter-y-md q-mx-md no-border-radius">
      <div
        class="q-gutter-y-md bg-white q-px-lg q-pb-md q-pt-sm q-mt-md q-mx-md rounded-borders"
      >
        <FormGeneratorWrapper
          v-if="!loading"
          :model="formResponse"
          :schema="schema"
          :attraction-code="`${schemaCode}${String(
            get(model, 'class', '')
          ).toUpperCase()}`"
          :hide-nulls="true"
        />
        <div v-if="!formResponse && !loading" class="full-width text-center">
          {{ $t('ResponseCard.noChecksResult') }}
        </div>
        <div class="q-mt-lg">
          <a
            target="_blank"
            :download="$t('ResponseCard.requestXML')"
            @click="downloadXml"
          >
            <q-btn
              dense
              :disable="!Boolean(get(model, 'originalMessageId'))"
              :style="{
                background: '#d9e2eb',
                padding: '8px 6px',
                color: '#222',
                fontSize: '12px',
                fontWeight: '400',
                lineHeight: '16px',
              }"
              class="cursor-pointer"
            >
              {{ $t('ResponseCard.downloadXML') }}
            </q-btn>
          </a>
          <div v-if="documents.length > 0">
            <div class="text-subtitle1">
              {{ $t('ResponseCard.ApplicationsTitle') }}
            </div>
            <a ref="application" />
            <q-list
              v-for="document in documents"
              :key="document.fileName"
              bordered
              separator
            >
              <q-item>
                <q-item-section> {{ document.fileName }}</q-item-section>
                <q-item-section avatar>
                  <q-btn
                    :label="$t('ResponseCard.downloadApplication')"
                    color="secondary"
                    size="sm"
                    @click="downloadApplicationFile(document.url)"
                  />
                </q-item-section>
              </q-item>
            </q-list>
          </div>
        </div>
      </div>
    </q-card>
  </div>
</template>

<script lang="ts">
// TODO Типы
import { Component, Prop, Mixins, Watch } from 'vue-property-decorator';
import Loadable from '@mixins/Loadable';
import FormGeneratorWrapper from '@components/common/node-generator/FormGeneratorWrapper.vue';
import {
  createDictionaryMapFromSchema,
  setValuesFromDictionaries,
} from '@utils/dict-map-utils';
import { customizeListData } from '@components/cards/inter_requests/data-customizations';
import { saveFileViaLink } from '@utils/files';
import S3UrlSignerFilesService from '@services/s3urlsigner/files';
import { BaseCardCommon } from '@/interfaces';
import { InteragencyApi } from '@openapi/registry-service';
import get from 'lodash/get';
import head from 'lodash/head';
import isPlainObject from 'lodash/isPlainObject';
import cloneDeep from 'lodash/cloneDeep';
import { DocumentApi } from '@openapi/document-registry';
import { InteragencyRequest } from '@interfaces/entities/InteragencyRequest';
import { Schema } from '@devsun/eva-models';
import { notifyError } from '@utils/notify';

const interagencyApi = new InteragencyApi();
const documentApi = new DocumentApi();

@Component({
  components: {
    FormGeneratorWrapper,
  },
  methods: {
    get,
  },
})
export default class InterRequestTabResponse extends Mixins(Loadable) {
  @Prop() common: BaseCardCommon;
  @Prop() model: InteragencyRequest;
  loading = false;
  statementId = '';
  schemaCode = 'InterRequests_CardsInterRequestTabResponse';
  schema: Schema.MetaClassSchemaRaw | any = {};
  formResponse: Record<string, unknown> | null = null;
  printResponse = null;
  dictionaryMap = {};

  get documents(): unknown[] {
    return this.model?.documents ?? [];
  }

  /**
   * Переименование ключей начинающихся с "extract_..." и "exract_..."
   * в "extract" и "exract"
   */
  get responseWithRenamedKeys(): Record<string, unknown> | null {
    const response = (this.model?.response as Record<string, unknown>) ?? null;

    if (!isPlainObject(response)) {
      return response;
    }

    const entries = Object.entries(response);
    const targetPrefixesRegExp = /^(ex(|t)ract)_.*/i;

    entries.forEach((item) => {
      const key = item[0];
      item[0] = key.replace(targetPrefixesRegExp, '$1');
    });

    return Object.fromEntries(entries);
  }

  get computedFormResponse(): Record<string, unknown> | null {
    if (!this.responseWithRenamedKeys) {
      return null;
    }

    let formResponse;

    switch (this.model.class) {
      case 'fns-inn-group':
        formResponse = {
          responseData: customizeListData(
            this.responseWithRenamedKeys,
            this.model.request,
            'SvedOtvet.smevFNSFNSINNGroupRes',
            'SvedFLGrup.params',
            (to: any, from: any) => {
              return to.IdZapros === from.guid;
            }
          ),
        };
        break;
      default:
        formResponse = {
          responseData: this.responseWithRenamedKeys,
        };
    }

    return formResponse;
  }

  @Watch('model')
  onModelChanged(val: InteragencyRequest): void {
    if (val?.response && val?.responseData === undefined) {
      this.getSchema(val)
        .then(async (schema) => {
          await this.initDictionaries(schema as Schema.MetaClassSchemaRaw);
          this.formResponse = this.computedFormResponse;
        })
        .then(() => {
          if (this.isFailedInterRequest(val)) {
            this.initErrorsData(cloneDeep(val));
          }
        })
        .finally(() => {
          this.loading = false;
        });
    }
  }

  @Watch('formResponse')
  async onFormResponseChanged(val: Record<string, unknown>): Promise<void> {
    this.setTotalModel(
      {
        responseData: await setValuesFromDictionaries(val, this.dictionaryMap),
      },
      this.model
    );
  }

  isFailedInterRequest(model: InteragencyRequest): boolean {
    return (
      ['fail', 'sendingFailed'].includes(model.status) ||
      model.response?.code === 'NO_DATA'
    );
  }

  downloadXml(): Promise<unknown> {
    return new Promise((resolve, reject) => {
      this.$store
        .dispatch('mz/history/getCurrentXml', {
          type: 'responseFsmev',
          id: this.model.originalMessageId,
        })
        .then((data) => {
          resolve(data);
        })
        .catch(() => {
          this.$store
            .dispatch('mz/history/getCurrentXml', {
              type: 'responseSmev',
              id: this.model.originalMessageId,
            })
            .then((data) => {
              resolve(data);
            })
            .catch((e) => {
              notifyError(this.$t('ResponseCard.noFile').toString());
              reject(e);
            });
        });
    });
  }

  setTotalModel(customObject: unknown, model: InteragencyRequest): void {
    let totalModel;

    if (!this.printResponse) {
      totalModel = Object.assign(customObject, model);
    } else {
      totalModel = { responseData: this.printResponse, ...model };
    }
    this.$store.commit('utils/cards/addModel', {
      model: totalModel,
      path: this.common.path,
    });
  }

  // Для формирования даных для печатной формы
  async initDictionaries(
    schema: Schema.MetaClassSchemaRaw
  ): Promise<void | unknown> {
    const schemaMap = schema.dictionaries ?? {};
    this.dictionaryMap = {
      ...schemaMap,
      ...createDictionaryMapFromSchema(schema),
    };
    const dicts = new Set(Object.values(this.dictionaryMap));

    if (Object.keys(this.dictionaryMap).length) {
      return this.$store.dispatch(
        'registryService/referenceBooks/initReferenceBooks',
        [...dicts].map((id: any) => {
          return { id };
        })
      );
    }
  }

  async getSchemaFromRegistry(serviceId: string): Promise<
    Schema.MetaClassSchemaRaw | undefined
  > {
    const FORM_KEY = 'formResponse';
    const mzClassName = get(this.model, 'class');

    try {
      const { data: interagencies } = await interagencyApi.pagingInteragency(
        undefined,
        undefined,
        `class==${mzClassName}`,
        undefined,
        undefined,
        FORM_KEY
      );
      const interagency = head(interagencies.records);
      const form = get(interagency, FORM_KEY);
      if (Array.isArray(form)) {
        const neededForm = form.find(f => f.parentServiceId === serviceId);
        console.log('neededForm', neededForm);
        if (neededForm) {
          return neededForm;
        }
        return form[0];
      }
      return form;
    } catch (err) {
      console.error(
        `[inter requests][get form schema from registry] ${mzClassName}`
      );
    }
  }

  async downloadApplicationFile(url: string): Promise<void> {
    try {
      const file = await S3UrlSignerFilesService.fetchFileFromS3ByUrl({
        url,
      });
      saveFileViaLink({
        anchor: this.$refs.application as HTMLAnchorElement,
        hrefData: file.presignedUrl,
        fileName: 'default.xml',
      });
    } catch (e: any) {
      notifyError(e.message.toString());
    }
  }

  async getSchema(
    model: InteragencyRequest
  ): Promise<Schema.MetaClassSchemaRaw | undefined> {
    const className = model.class;
    const schemaCode = `${this.schemaCode}${String(className).toUpperCase()}`;

    if (this.isFailedInterRequest(model)) {
      return this.getErrorsSchema();
    }

    try {
      const { data: statement } = await documentApi.getDocument(
        'Applications',
         this.statementId
      );
      const serviceID = get(statement, 'system.serviceId') || get(model, 'statement.system.serviceId');
      let schema = await this.getSchemaFromRegistry(serviceID);

      if (!schema) {

        notifyError(
          `[MZ Response tab] No form (view schema) found in service registry for mz: ${this.model?.requestName} ${this.model?.class}`
        );
        console.warn('--------------------------');
        console.warn('--------------------------');
        console.warn(
          '[MZ Response tab] No form (view schema) found in service registry for mz:',
          get(this.model, 'requestName'),
          get(this.model, 'class')
        );
        serviceID &&
          console.warn(
            'You can add a form at this address:',
            `${location.origin}/microws/cards/services/${serviceID}?active=forms&components=index,processes,forms,directories,verifications,documents,interagencies,stages,form_model,digital_regulations`
          );
        console.warn('--------------------------');
        console.warn('--------------------------');

        schema = await this.$store.dispatch(
          'utils/components/fetchModelByCode',
          schemaCode
        );
      }

      this.schema = schema;

      return schema;
    } catch (err) {
      notifyError(err.message.toString());

      console.error('[inter requests][response tab][get schema]', err);
    }
  }

  getErrorsSchema(): Promise<Schema.MetaClassSchemaRaw> {
    return new Promise((resolve, reject) => {
      // TODO : Request this from SchemaRegistry. This one requests a static common one
      // Have to make a registry/ui for common schemas
      this.$store
        .dispatch(
          'utils/components/fetchModelByCode',
          `${this.schemaCode}Errors`
        )
        .then((errorsSchema) => {
          this.schema = errorsSchema;
          resolve(this.schema);
        })
        .catch(() => {
          notifyError(this.$t('StatementCard.errorLoadingModel').toString());
          reject();
        });
    });
  }

  initErrorsData(data: InteragencyRequest): void {
    if (this.formResponse) {
      this.$set(this.formResponse, 'response', data.response);
    }
  }
}
</script>
