<i18n>
{
  "en": {
    "statements": {
      "UploaderDialog": {
        "addingDocument": "Adding a document",
        "attach": "Attach",
        "documentsUploadedSuccessfully": "Documents uploaded successfully",
        "invalidResultFile": "Invalid file format. The resulting document must be in HTML, PDF, DOCX format",
        "invalidFile": "Invalid file format",
        "inputLabel": "Name"
      }
    }
  },
  "ru": {
    "statements": {
      "UploaderDialog": {
        "addingDocument": "Добавление документа",
        "attach": "Прикрепить",
        "documentsUploadedSuccessfully": "Документы успешно загружены",
        "invalidResultFile": "Недопустимый формат файла. Результирующий документ должен быть в формате HTML, PDF, DOCX",
        "invalidFile": "Недопустимый формат файла",
        "inputLabel": "Наименование"
      }
    }
  }
}
</i18n>

<template>
  <div>
    <div
      v-if="$slots.button"
      class="cursor-pointer"
      v-bind="button.props"
      @click="doAction"
    >
      <slot name="button"> </slot>
    </div>

    <q-btn
      v-else
      :disable="disableAllButtons"
      class="q-ml-sm"
      outline
      :label="get(buttonSettings, 'props.label')"
      :color="get(buttonSettings, 'props.color')"
      v-bind="button.props"
      @click="doAction"
    />
    <q-dialog v-model="value" :persistent="loading">
      <q-card class="no-shadow" style="max-width: 80vw; width: 700px">
        <q-card-section class="text-h6">
          {{ $t('statements.UploaderDialog.addingDocument') }}
        </q-card-section>
        <q-card-section>
          <base-uploader
            :with-input="false"
            :accept="accept"
            :rules-for-rejected="true"
            :rules="fileRules"
            :need-file="true"
            :input-label="$t('statements.UploaderDialog.inputLabel')"
            @input="(inputFiles) => (files = inputFiles)"
            @upload="uploadDocuments"
          />
        </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">
import { Component, Prop, Vue } from 'vue-property-decorator';
import {
  resDocNameLengthFileRule,
  resDocNameFileRule,
} from '@utils/field-validation/documents';
import { BaseCardCommon } from '@/interfaces';
import S3UrlSignerFilesService from '@services/s3urlsigner/files';
import get from 'lodash/get';
import { WorkflowServiceApi } from '@openapi/wf';
import { DocumentApi } from '@openapi/document-registry';
import { notifyError, notifySuccess } from '@utils/notify';
import { extractFileName } from '@/utils/files';

const wfApi = new WorkflowServiceApi();
const documentApi = new DocumentApi();

function getFile(files?: File[]): File | undefined {
  return get(files, 0);
}

@Component({
  methods: {
    get,
  },
})
export default class AdditionalResultDocumentDialog extends Vue {
  @Prop({}) private row?: any;
  @Prop({}) private common?: BaseCardCommon;
  @Prop({}) private model?: any;
  @Prop({}) private disableAllButtons?: boolean;
  @Prop({}) private userTask?: any;
  @Prop({}) private buttonSettings?: any;

  protected loading = false;
  protected button = {
    props: {
      color: 'primary',
      label: this.$t('statements.UploaderDialog.attach'),
      loading: false,
    },
  };

  protected documentId = '';
  protected files: File[] = [];
  protected documentTypeObject = null;
  protected comment = '';
  protected value = false;

  protected get accept(): string {
    if (['09.1', '09.4'].includes(get(this.model, 'system.status.system'))) {
      return '.pdf, .docx, .html, .zip, .tgz, .cert, .7z';
    }
    return '.pdf, .docx, .html';
  }

  protected get fileRules(): { (val: File[]): boolean | string }[] {
    return [this.validationRule, resDocNameLengthFileRule, resDocNameFileRule];
  }

  protected get validationMessage(): string {
    return String(this.$t('statements.UploaderDialog.invalidResultFile'));
  }

  private validationRule(val: File[]): boolean | string {
    const file = val[0] || null;
    return !val.length
      ? true
      : this.checkFileFormat(file) || this.validationMessage;
  }

  private checkFileFormat(file: File | null): boolean {
    const accepts = this.accept.split(', ');
    if (file) {
      const extension: any = file.name?.split('.').pop() || '';
      return accepts.includes(`.${extension.toLowerCase()}`);
    }
    return false;
  }

  public doAction(): void {
    this.value = true;
  }

  public createDocument(
    opts: Options,
    s3Url: string | undefined = undefined
  ): void {
    const file = getFile(opts.files);
    const documentObject = {
      type: {
        code: 'AdditionalResultDocument',
        name: 'Дополнительный документ',
      },
      file: {
        name: extractFileName(file) || null,
        url: s3Url || null,
      },
    };
    wfApi.submitForm(get(this.userTask, 'userTask.taskId'), {
      id: 'addAdditionalResultDocument',
      data: {
        document: documentObject,
      },
    });
  }

  public saveDocument(
    opts: Options,
    s3Url: string | undefined = undefined
  ): void {
    const file = getFile(opts.files);

    const documentObject: any = Object.assign(
      {},
      {
        id: get(this.row, 'id'),
        modified: get(this.row, 'modified'),
        source: get(this.row, 'source'),
        schema: get(this.row, 'schema'),
        type: {
          code: 'AdditionalResultDocument',
          name: 'Дополнительный документ',
        },
      }
    );

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

    documentApi
      .updateDocument(documentObject.schema, [documentObject])
      .then(() => {
        wfApi.submitForm(get(this.userTask, 'userTask.taskId'), {
          id: 'updateAdditionalResultDocument',
          data: {
            docIds: [documentObject.id],
          },
        });
      });
  }

  public uploadDocuments(data: Options, done: { (): void }): void {
    this.loading = true;
    const uploadFile = (opts: Options) => {
      const file = getFile(opts.files);
      return S3UrlSignerFilesService.uploadFileToS3ByPath({
        file,
        path: `Applications/${get(this.common, 'id')}/file/${extractFileName(
          file
        )}`,
      })
        .then((s3Url) => {
          notifySuccess(
            String(
              this.$t('statements.DocumentsCard.documentsUploadedSuccessfully')
            )
          );
          if (this.row) {
            this.saveDocument(opts, s3Url);
          } else {
            this.createDocument(opts, s3Url);
          }
        })
        .catch(() => {
          notifyError(
            String(this.$t('statements.DocumentsCard.errorLoadingDocuments'))
          );
          this.loading = false;
        })
        .finally(() => {
          this.button.props.loading = false;
          this.loading = false;
          this.value = false;
        });
    };

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

    if (files) {
      opts.files = files;
    }

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

    if (Array.isArray(opts.files) && opts.files.length) {
      uploadFile(opts).finally(() => {
        done();
      });
    } else {
      if (this.row) {
        this.saveDocument(opts);
      } else {
        this.createDocument(opts);
      }
      this.button.props.loading = false;
      this.loading = false;
      this.value = false;
    }
  }
}

declare interface Options {
  files?: File[];
  description?: string;
}
</script>
