<i18n>
{
  "en": {
    "statements": {
      "DocumentDialog": {
        "addingDocument": "Adding a document",
        "generate": "Generate",
        "documentTypeLabel": "Document type",
        "formingSolution": "Forming a solution"
      }
    }
  },
  "ru": {
    "statements": {
      "DocumentDialog": {
        "addingDocument": "Добавление документа",
        "generate": "Сформировать",
        "documentTypeLabel": "Тип документа",
        "formingSolution": "Формирование проекта решения"
      }
    }
  }
}
</i18n>

<template>
  <div>
    <!--    todo rethink buttons-->
    <q-btn
      :disable="disableAllButtons || buttonDisable"
      class="q-ml-sm"
      outline
      :label="get(buttonSettings, 'props.label')"
      :color="get(buttonSettings, 'props.color')"
      :class="{ hidden: !get(buttonSettings, 'props.visible', true) }"
      @click="doAction"
      v-bind="button.props"
    />
    <!-- TODO: Доделать дефолтную кнопку с настраеваемым id(props) и label'ом  -->
    <q-dialog v-model="dialogVisible" :persistent="loading">
      <q-card
        class="no-shadow"
        :style="{
          maxWidth: '80vw',
          width: isResultDocument ? '1100px' : '700px',
        }"
      >
        <q-card-section class="text-h6">
          {{
            isResultDocument
              ? $t('statements.DocumentDialog.formingSolution')
              : $t('statements.DocumentDialog.addingDocument')
          }}
        </q-card-section>
        <q-card-section class="full-width q-gutter-y-md">
          <q-select
            :options="availableDocumentTypeOptions"
            emit-value
            filled
            :label="$t('statements.DocumentDialog.documentTypeLabel')"
            map-options
            :hide-dropdown-icon="disabledSelectDocument"
            :disable="disabledSelectDocument"
            v-model="documentTypeObject"
            :popup-content-style="{ width: '40%' }"
          />
          <component
            ref="form"
            v-if="uploadFormComponent"
            :is="uploadFormComponent"
            @update="updateUploadFormModel"
            @update-validation="isValidFormValue = $event"
            :type-object="documentTypeObject"
            :form="form"
            :form-defaults="formDefaults"
            :sub="sub"
            :base-schema="baseSchema"
            mode="create"
          /><!-- TODO: Доделать подгрузку форм -->
        </q-card-section>
        <q-card-section
          class="full-width flex justify-end"
          v-if="isResultDocument"
        >
          <q-btn
            @click="uploadDocuments"
            :label="
              isResultDocument
                ? $t('statements.DocumentDialog.generate')
                : $t('base.uploader.upload')
            "
            :disable="!(documentTypeObject && isValidFormValue)"
            :loading="model.loading"
            color="primary"
          />
        </q-card-section>
        <q-card-section v-else>
          <base-uploader
            @input="(upFiles) => (files = upFiles)"
            @upload="uploadDocuments"
            :disable="disableInputFile"
            :description="comment"
            :need-file="isFileNeeded"
            accept=".xml, .zip, .7z, .rar, .ppt, .odt, .pdf, .doc, .docx, .xls, .xlsx, .txt, image/*"
          />
        </q-card-section>
        <q-inner-loading :showing="loading">
          <q-spinner-gears color="primary" size="50px" />
        </q-inner-loading>
      </q-card>
    </q-dialog>
  </div>
</template>

<script lang="ts">
// @ts-nocheck

import getUUID from 'uuid-by-string';
import {
  convertDateFormatWithoutLocale,
  convertDateFromBackendFormat,
  convertDateToBackendFormat,
} from '@utils/format-date';
import { DateFormat } from '@constants/utils/format-date';
import S3UrlSignerFilesService from '@services/s3urlsigner/files';
import { CardNeedToUpdateType } from '@constants/models/Card';
import get from 'lodash/get';
import isObject from 'lodash/isObject';
import isArray from 'lodash/isArray';
import merge from 'lodash/merge';
import cloneDeep from 'lodash/cloneDeep';
import isEqual from 'lodash/isEqual';
import { DocumentApi } from '@openapi/document-registry';
import { notifyError, notifySuccess } from '@utils/notify';

const documentApi = new DocumentApi();

export default {
  name: 'document-dialog',
  props: [
    'common',
    'model',
    'disable-all-buttons',
    'user-task',
    'button-settings',
  ],

  computed: {
    isFileNeeded() {
      return !this.documentTypeObject?.data.optional;
    },
    checksValidateCondition() {
      return (
        get(this.userTask, 'userTask.outData.checkListIsMandatory') &&
        !this.$store.getters[
          'commonComponents/baseChecksTable/allChecksHaveBeenPassed'
        ] &&
        get(this.model, 'decisionData.manualVerificationExist')
      );
    },
    buttonDisable() {
      return get(
        this.buttonSettings,
        'props.disable',
        get(this.button, 'props.disable')
      );
    },
    sub() {
      const buttonId = get(this.buttonSettings, 'id');
      if (!['accept', 'reject', 'refuse'].includes(buttonId)) return;
      return [get(this.model, 'statement.goal')];
    },
    baseSchema() {
      const buttonId = get(this.buttonSettings, 'id');
      if (!['reject', 'refuse'].includes(buttonId)) return;
      return {};
    },
    actions() {
      return get(this.userTask, 'userTask.outData.actions') || [];
    },
    availableDocs() {
      return get(
        this.userTask,
        `userTask.outData.availableDocs["${this.buttonSettings.id}"]`,
        []
      );
    },
    decisionFormDataAdditional() {
      return (
        get(
          this.userTask,
          `userTask.outData.decisionFormDataAdditional.${this.buttonSettings.id}`
        ) || {}
      );
    },
    documentsFormKey() {
      if (this.userTask && this.userTask.userTask) {
        return this.userTask.userTask.formKey;
      } else {
        return undefined;
      }
    },
    decisionNumbers() {
      return get(this.userTask, 'userTask.outData.decisionNumbers', {});
    },
    isResultDocument() {
      const buttonId = get(this.buttonSettings, 'id');

      return ['refuse', 'reject', 'accept'].includes(buttonId);
    },
    serviceMeta() {
      return this.$store.getters['registryService/services/servicesCard'];
    },
    disabledSelectDocument() {
      return this.availableDocumentTypeOptions.length < 2;
    },
    disableInputFile() {
      return !this.documentTypeObject;
    },
  },

  data() {
    return {
      loading: false,
      button: {
        props: {
          color: 'red',
          label: 'Отказать',
          loading: false,
        },
        id: '',
      },
      comment: '',
      files: [],
      documentTypeOptions: [],
      availableDocumentTypeOptions: [],
      isUploaded: false,
      documentTypeObject: null,
      isEdit: false,
      uploadFormComponent: undefined,
      documentId: '',
      isValidFormValue: true,
      form: {
        dateRegistered: '',
      },
      formDefaults: {},
      dialogVisible: false,
    };
  },
  methods: {
    get,
    isDate2(date) {
      if (!date) return false;
      if (typeof date === 'string')
        return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(date);
      return date instanceof Date;
    },
    availableDocumentTypeOptionsByAction() {
      if (this.documentTypeOptions && this.availableDocs) {
        const availableDocs = this.availableDocs;

        return this.documentTypeOptions.filter((doc) => {
          return (
            Array.isArray(availableDocs) &&
            availableDocs.find(
              (d) => (isObject(d) && d.code === doc.type) || d === doc.type
            )
          );
        });
      }
    },
    doAction() {
      if (!this.checksValidateCondition) {
        this.initDocumentType()
          .then(() => {
            this.initUploader();
          })
          .catch((e) => {
            console.error('Document dialog: ' + e);
            notifyError('initDocumentType error');
          });
        this.dialogVisible = true;
        this.$recordActivity({
          buttonCode: 'application_refuse',
          extraInfo: {
            previewInfo: [
              {
                value: this.model?.common?.orderId,
                label: 'номер',
              },
            ],
          },
        });
      } else {
        this.$emit('commonModels', {
          checks: {
            needToBeValidated: true,
          },
        });
      }
    },
    uploadDocuments(data, done) {
      if (!this.isValidFormValue) {
        this.$refs.form.triggerValidation();
        return;
      }
      this.$recordActivity({
        buttonCode: 'application_form',
        extraInfo: {
          previewInfo: [
            {
              value: this.model?.common?.orderId,
              label: 'номер',
            },
          ],
        },
      });
      this.loading = true;
      const uploadFile = ({ opts, formData }) => {
        const fileName = opts.files[0].name;
        const ext = fileName.split('.').pop();
        const UUIDFromFileName = `${getUUID(fileName)}.${ext}`;

        return S3UrlSignerFilesService.uploadFileToS3ByPath({
          file: opts.files[0],
          path: `Applications/${this.common.id}/file/${UUIDFromFileName}`,
        })
          .then((s3Url) => {
            notifySuccess(
              this.$t('statements.DocumentsCard.documentsUploadedSuccessfully')
            );
            this.saveDocument(opts, formData, s3Url);
          })
          .catch(() => {
            notifyError(
              this.$t('statements.DocumentsCard.errorLoadingDocuments')
            );
            this.loading = false;
          });
      };

      const opts = {
        files: get(data, 'files') || [],
      };
      const description = (get(data, 'description') || '').trim();

      if (description) {
        opts.description = description.trim();
      }

      if (opts.files.length) {
        uploadFile({
          opts,
          formData: Object.assign({}, this.form),
        }).finally(() => {
          done();

          this.dialogVisible = false;
        });
      } else {
        this.saveDocument(opts, this.form);
      }
    },
    updateUploadFormModel(model) {
      if (isEqual(this.form, model)) return;
      const updatedObject = {};
      Object.keys(model).forEach((key) => {
        updatedObject[key] = model[key];
      });
      this.form = updatedObject;
    },
    initDocumentType() {
      return new Promise((resolve, reject) => {
        const comparator = this.$store.getters['i18N/localeComparator'];

        const docs = this.serviceMeta?.documents;
        if (docs) {
          this.documentTypeOptions = docs
            .map((document) => ({
              type: document.code,
              label: document.name,
              data: document,
            }))
            .sort((a, b) => comparator(a.label, b.label));

          resolve(this.documentTypeOptions);
        } else {
          reject();
        }
      });
    },
    getDefaults(buttonId) {
      const defaults = Object.create(null);

      defaults.resNumber =
        get(this.userTask, `userTask.outData.decisionNumbers.${buttonId}`) ||
        '';

      return Object.assign(
        defaults,
        get(this.userTask, `userTask.outData.decisionFormData`),
        this.decisionFormDataAdditional,
        buttonId === 'reject' || buttonId === 'refuse'
          ? {
              resDate: convertDateFromBackendFormat(
                new Date(),
                DateFormat.date
              ),
            }
          : {}
      );
    },
    initUploader(buttonId) {
      buttonId = buttonId || get(this.buttonSettings, 'id');

      this.button.id = buttonId;
      this.isEdit = false;
      this.comment = '';
      this.files = [];
      this.isUploaded = false;
      this.form.dateRegistered = '';
      this.documentId = '';

      this.availableDocumentTypeOptions = this.availableDocumentTypeOptionsByAction(
        buttonId
      );
      const docForm = get(
        this.userTask,
        `userTask.outData.availableDocs.${buttonId}[0]`
      );

      const docTypeFromUT = isObject(docForm) ? docForm?.code : docForm;

      if (this.availableDocumentTypeOptions.length === 1) {
        this.documentTypeObject = this.availableDocumentTypeOptions.find(
          (doc) => doc.type === docTypeFromUT
        );

        // this.documentTypeObject.form = docTypeFromUT;

        if (isObject(docForm) && docForm.form) {
          this.documentTypeObject.form = docForm.form;
        }
      }

      this.formDefaults = this.getDefaults(buttonId);

      this.fetchForm();
    },
    submit({ buttonId, data }) {
      this.$emit('submit', {
        buttonId,
        data,
        force: true,
      });
    },
    fetchForm() {
      const rejectCodes =
        this.serviceMeta.verifications?.map((v) => v.rejectCode) || [];
      const invertLabels =
        this.serviceMeta.verifications?.map((v) => v.code + 'InvertLabel') ||
        [];
      // #PreviousDocResult Добавляет атрибуты с предыдущего документа (если пришел со схемы)
      const previousDocResults = get(
        this.userTask,
        'userTask.outData.previousDocResult'
      );

      if (previousDocResults && isArray(previousDocResults)) {
        const previousDocResult = get(previousDocResults, '[0]');

        if (previousDocResult && isObject(previousDocResult)) {
          const previous = [...rejectCodes, ...invertLabels].reduce(
            (obj, prop) => {
              delete obj[prop];
              return obj;
            },
            cloneDeep(previousDocResult)
          );
          this.form = merge({}, this.form, previous);
          this.formDefaults = merge({}, this.formDefaults, previous);
        }
      }
      // #endPreviousDocResult

      if (this.uploadFormComponent) {
        return;
      }
      this.uploadFormComponent = this.$GlobalComponentImporter.registerComponent(
        this.documentsFormKey,
        'forms/'
      );
    },
    async saveDocument(opts, formData, s3Url = undefined) {
      const form = this.$refs.form;

      let generatedFields = {};
      if (form) {
        if (typeof form.generateResolutionDocFields === 'function') {
          try {
            generatedFields = await form.generateResolutionDocFields();
          } catch (e) {
            console.error('didnt found generated fields', e);
          }
        }

        if (!this.isValidFormValue) {
          this.loading = false;
          return;
        }
      }

      // Ниже в uploadForm данные из decisionFormDataAdditional дополняются данными из форм-генератора
      // для прокидывания некоторых свойств в шаблон печати в обход форм-генератора (касается инвертированных label'ов)
      const uploadForm = Object.assign(
        {},
        this.decisionFormDataAdditional,
        formData,
        generatedFields
      );
      const file = opts.files[0];
      const comment = opts.description || '';
      const dateRegistered = convertDateFormatWithoutLocale(
        formData.dateRegistered
      );

      for (const key in uploadForm) {
        const value = uploadForm[key];
        if (value === undefined) {
          delete uploadForm[key];
        } else if (this.isDate2(value)) {
          const date = convertDateFormatWithoutLocale(value);
          uploadForm[key] = convertDateToBackendFormat(date);
        }
      }

      // #region ВРЕМЕННЫЙ КОД
      // в кратце надо что бы сама модель сервиса начала различать документы не только на состояния и отказы/разрешения как сейчас,
      // но и в зависимости от других переменных, например, разные цели по одной услуге
      // таск: https://jira.devsun.ru/browse/PGS-198

      // Антонина Аркуша, [8 Oct 2020 at 15:41:05]:
      // этого можно будет избежать
      // когда в настройке базового БП будет анализ цели при выборе дока, сейчас смотрим только на stage
      // https://jira.devsun.ru/browse/PGS-246
      // https://jira.devsun.ru/browse/PGS-236
      const service = this.model?.service;
      const goal = this.model?.statement?.goal;
      const RSIZS = 'Услуга РС ИЖС';
      const RVIZS = 'РВ ИЖС';
      const ADDRESSING = 'Услуга Адресация';

      if ([RSIZS, RVIZS].includes(service)) {
        const objectUseType = this.model?.statement?.variantChoice
          ?.applicantRightEGRNRegistered;
        let objectType;

        if (service === RSIZS) {
          objectType = this.model?.statement?.object?.useTypeRadio;

          uploadForm.direction = [1, 2].includes(goal)
            ? 'Sending notification'
            : null;
          uploadForm.correction = [3, 4].includes(goal)
            ? 'Sending notification'
            : null;
        }

        if (service === RVIZS) {
          objectType = this.model?.statement?.object?.objectUse;
        }

        switch (objectUseType) {
          case 1:
            uploadForm.objectUseType = 'строительства';
            break;

          case 2:
            uploadForm.objectUseType = 'реконструкции';
            break;
        }

        switch (objectType) {
          case 1:
            uploadForm.objectType =
              'объекта индивидуального жилищного строительства';
            break;

          case 2:
            uploadForm.objectType = 'садового дома';
            break;
        }

        const goals = [1, 2, 3, 4];

        // https://jira.devsun.ru/browse/PGS-250 this should explain it
        goals.forEach((goalIt) => {
          if (service === RVIZS && goalIt === 2) {
            uploadForm[`goal${goalIt}`] = null;

            return;
          }

          const goalToCompare =
            service === RVIZS && goalIt > 2 ? goalIt - 1 : goalIt;

          uploadForm[`goal${goalIt}`] = goalToCompare === goal ? 'true' : null;
        });
      }

      if (service === ADDRESSING) {
        if (this.model?.statement?.variantChoice?.addressObject?.landPlot) {
          uploadForm.landPlot = 'Земельный участок';
        }
        if (this.model?.statement?.variantChoice?.addressObject?.build) {
          uploadForm.build = 'Здание (строение), сооружение';
        }
        if (this.model?.statement?.variantChoice?.addressObject?.premise) {
          uploadForm.premise = 'Помещение';
        }
        if (this.model?.statement?.variantChoice?.addressObject?.parkingPlace) {
          uploadForm.parkingPlace = 'Машино-место';
        }
      }
      // #endregion

      const documentTypeObjectCode = get(this.documentTypeObject, 'type');
      const documentTypeObjectLabel = get(this.documentTypeObject, 'label');
      const documentObject = Object.assign({}, uploadForm, {
        id: this.documentId,
        resNumber: formData.resNumber,
        dateRegistered: convertDateToBackendFormat(dateRegistered),
        type: {
          code: documentTypeObjectCode,
          name: documentTypeObjectLabel,
        },
        schema: this.schema,
        comment,
        modified: this.documentModified,
      });

      const submit = () => {
        if (this.isEdit) {
          documentApi
            .updateDocument(documentObject.schema, [
              {
                ...documentObject,
                source: 'Result',
              },
            ])
            .then(() => {
              this.$store.commit(
                'utils/cards/needToUpdate',
                CardNeedToUpdateType.MODEL
              );
            });
        } else if (this.userTask) {
          this.submit({
            buttonId: this.buttonSettings.id,
            data: {
              document: {
                ...documentObject,
              },
            },
            force: true,
          });
        }
      };

      if (file) {
        documentObject.file = {
          name: file.name,
          url: s3Url,
        };
      }

      submit();

      this.dialogVisible = false;
      this.loading = false;
    },
  },
};
</script>
