<template>
  <div class="q-pa-md q-gutter-y-md">
    <div
      class="flex justify-between items-center bg-white q-pa-md rounded-borders"
    >
      <div class="column full-width">
        <div>
          <div
            class="text-h6 flex items-center q-gutter-y-md text-grey-9 col q-pr-md"
          >
            <q-btn
              :loading="loading"
              padding="xs"
              class="text-grey-7 q-mr-md"
              color="grey-3"
              icon="arrow_back"
              @click="returnToParentView(parentRoute)"
            />
            <div class="text-h5">{{
              $t('registries.unloadingList.title')
            }}</div>
            <q-space />
            <div class="row items-center q-gutter-x-md q-gutter-y-sm">
              <q-btn
                v-if="
                  $AC.haveOneOfScope([
                    USER_SCOPES.UNLOADING_CREATE,
                    USER_SCOPES.UNLOADING_LINK_BTN,
                  ])
                "
                :label="$t('registries.unloadingList.orderGenerateBtn')"
                color="primary"
                :loading="loading"
                @click="GenerateAnOrder"
              />
              <q-btn
                v-if="$AC.haveScope(USER_SCOPES.UNLOADING_DOWNLOAD)"
                color="primary"
                :label="$t('registries.unloadingList.archiveDownloadBtn')"
                @click="exportRecords"
                :loading="loading"
              />
              <q-btn
                v-if="$AC.haveScope(USER_SCOPES.IMPORT_UFK)"
                color="primary"
                label="Импорт из УФК"
                :loading="loading"
                @click="importUFK"
              />
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="bg-white rounded-borders">
      <BaseTable
        :columns="columns"
        :data="data"
        :selected.sync="selected"
        :pagination.sync="pagination"
        :loading="tableLoading"
        selection="multiple"
        @update:selected="selectionHandler"
        @update="updateTableData"
        @requestTable="updateTableData"
      >
        <template #search>
          <SearchBar
            :loading="loading"
            :show-save-button="true"
            @query="search"
            @save-data="exportRecordsByIds"
          />
        </template>
        <template v-slot:body-item-selection="scope">
          <q-checkbox
            :disable="!scope.props.row.signed && !scope.props.row.cancelDate"
            v-model="scope.props.selected"
          />
        </template>
        <template v-slot:body-item-sign="props">
          <div class="row no-wrap text-no-wrap float-right">
            <q-btn
              flat
              dense
              icon="info"
              size="16"
              style="color: rgba(0, 0, 0, 0.54)"
              color="primary"
              @click="annulInfo(props.row)"
            >
              <q-tooltip>
                {{ $t('registries.objectCard.annulInfo') }}
              </q-tooltip>
            </q-btn>
            <base-preview extension="pdf" :s3Url="get(props.row, 'reportLink')">
              <q-btn
                :disable="
                  !$AC.haveScope(USER_SCOPES.UNLOADING_PREVIEW) ||
                  !get(props.row, 'reportLink')
                "
                flat
                dense
                icon="search"
                size="16"
                style="color: rgba(0, 0, 0, 0.54)"
                color="primary"
              >
                <template #loading>
                  <q-spinner-gears />
                </template>
                <q-tooltip>
                  {{ $t('registries.objectCard.preview') }}
                </q-tooltip>
              </q-btn>
            </base-preview>

            <q-btn
              :disable="
                !$AC.haveScope(USER_SCOPES.UNLOADING_DOWNLOAD_PDF) ||
                !get(props.row, 'reportLink')
              "
              flat
              dense
              icon="arrow_downward"
              size="16"
              style="color: rgba(0, 0, 0, 0.54)"
              color="primary"
              @click="fetchDocumentAttachment(props.row)"
            >
              <q-tooltip>
                {{ $t('registries.objectCard.download') }}
              </q-tooltip>
            </q-btn>

            <q-btn
              v-if="props.row.signed"
              :disable="
                !$AC.haveScope(USER_SCOPES.UNLOADING_SIGN_INFO) ||
                !get(props.row, 'certificate')
              "
              flat
              dense
              icon="gesture"
              size="16"
              style="color: rgba(0, 0, 0, 0.54)"
              color="positive"
              @click="getSignInfo(props.row)"
            >
              <q-tooltip>
                {{ $t('registries.objectCard.viewingEDSData') }}
              </q-tooltip>
            </q-btn>
            <q-btn
              v-else
              :disable="
                !$AC.haveScope(USER_SCOPES.UNLOADING_SIGN) ||
                !get(props.row, 'reportLink') ||
                !get(props.row, 'dataFileLink') ||
                !!get(props.row, 'cancelDate')
              "
              flat
              dense
              icon="gesture"
              size="16"
              style="color: rgba(0, 0, 0, 0.54)"
              color="primary"
              @click="addSign(props.row)"
            >
              <q-tooltip>
                {{ $t('registries.objectCard.addEDS') }}
              </q-tooltip>
            </q-btn>
            <AnnulUnloading
              v-if="
                $AC.haveOneOfScope([
                  USER_SCOPES.CLOUD_ADMIN,
                  USER_SCOPES.UNLOADING_CANCEL,
                ])
              "
              @update="updateTableData"
              :registry="props.row"
              :registryCode="degaultRegistryCode"
              :processKey="degaultProcessKey"
              :user-id="$store.getters['oidcClient/currentUser'].sub"
            />
          </div>
        </template>
      </BaseTable>
      <UploadPaymentStatus
        :open.sync="uploadModal"
        :title="$t('registries.unloadingList.titleDialog')"
        @upload="updateTableData"
      />
      <UploadSignDialog
        :openDialog.sync="signModal"
        :model="currentItem"
        :processInfo="currentProcess"
        @listRefresh="updateTableData"
      />
      <SignInfoDialog
        :openDialog.sync="signInfoModal"
        :model="currentItem"
        @listRefresh="updateTableData"
      />
      <AnnulInfoDialog :openDialog.sync="annulInfoModal" :model="currentItem" />
      <a ref="export" />
    </div>
  </div>
</template>

<script lang="ts">
import { Component } from 'vue-property-decorator';
import { mixins } from 'vue-class-component';
import ReturnToParentView from '@mixins/ReturnToParentView';
import {
  ExportRegistryKompensDetskOtdMIR,
  RegistryApi,
} from '@openapi/registry-data/api';
import { convertDateFromTimestamp } from '@utils/format-date';
import { DateFormat } from '@constants/utils/format-date';
import QColumn from '@/types/QColumn';
import UploadPaymentStatus from '@components/registries/upload_payment_status.vue';
import { Route } from 'vue-router/types';
import { TablePagination } from '@models/base/TablePagination';
import UploadSignDialog from '@components/registries/upload_sign_dialog.vue';
import SignInfoDialog from '@components/registries/sign_info_dialog.vue';
import AnnulInfoDialog from '@components/registries/annul_info_dialog.vue';
import S3UrlSignerFilesService from '@services/s3urlsigner/files';
import { saveAs } from 'file-saver';
import SearchBar from '@components/registries/base-search-bar.vue';
import { USER_SCOPES } from '@constants/entities/Scope';
import get from 'lodash/get';
import SearchQuery from '@interfaces/entities/SearchQuery';
import axios from 'axios';
import AnnulUnloading from '@components/registries/annul_unloading.vue';
import { notifyError, notifySuccess } from '@utils/notify';


const REGISTRY_KOMPENS_DETSK_OTD_MIR_CREATE_UPLOADING_CANCEL_PROCESS =
  'RegistryKompensDectskOtdMIRCreateUploadingCancel';
const REGISTRY_KOMPENS_DETSK_OTD_MIR_REGISTRY_CODE =
  'RegistryKompensDetskOtdMIR';

const CHILDRENS_REST_CASHBACK_UPLOADING_PROCESS__CODE =
  'RegistryKompensDectskOtdMIRCreateUploading';
const REGISTRIES_LIST_URL = '/registries';
const CHILDRENS_REST_CASHBACK_CODE = 'RegistryKompensDetskOtdMIR';

@Component({
  components: {
    AnnulUnloading,
    SearchBar,
    UploadPaymentStatus,
    UploadSignDialog,
    SignInfoDialog,
    AnnulInfoDialog,
  },
  methods: {
    get,
  },
})
export default class UnloadingList extends mixins(ReturnToParentView) {
  selected: Array<ExportRegistryKompensDetskOtdMIR> = [];
  data: Array<ExportRegistryKompensDetskOtdMIR> = [];
  searchQuery: SearchQuery;
  queryString = '';
  fulltextString = '';
  currentProcess: Prosess | null = null;
  tableLoading = false;
  currentItem: ExportRegistryKompensDetskOtdMIR | null = null;
  loading = false;
  uploadModal = false;
  signModal = false;
  signInfoModal = false;
  annulInfoModal = false;
  pagination = new TablePagination({
    rowsPerPage: 100,
    descending: true,
    sortBy: 'created',
  });

  USER_SCOPES = USER_SCOPES;
  degaultProcessKey = REGISTRY_KOMPENS_DETSK_OTD_MIR_CREATE_UPLOADING_CANCEL_PROCESS
  degaultRegistryCode = REGISTRY_KOMPENS_DETSK_OTD_MIR_REGISTRY_CODE

  get parentRoute(): { name: string } | string {
    const registryListExists =
      this.$router.$history.findIndex(
        (route: Route) => route.name === 'registry-list'
      ) !== -1;
    if (registryListExists) {
      return { name: 'registry-list' };
    }
    return REGISTRIES_LIST_URL;
  }

  get columns(): Array<QColumn> {
    return [
      {
        align: 'left',
        field: 'title',
        label: this.$t('registries.unloadingList.name'),
        name: 'title',
        required: true,
        sortable: true,
      },
      {
        align: 'left',
        label: this.$t('registries.unloadingList.createDate'),
        field: 'created',
        format: (val: any) =>
          val ? convertDateFromTimestamp(val, DateFormat.date) : '',
        name: 'created',
        required: true,
        sortable: true,
      },
      {
        align: 'left',
        label: this.$t('registries.unloadingList.departmentName'),
        field: 'departmentName',
        name: 'departmentName',
        required: true,
        sortable: true,
      },
      {
        align: 'left',
        label: this.$t('registries.unloadingList.region'),
        field: 'regionName',
        name: 'regionName',
        required: true,
        sortable: true,
      },
      {
        align: 'left',
        label: this.$t('registries.unloadingList.state'),
        field: 'state',
        name: 'state',
        required: true,
        sortable: false,
      },
      {
        align: 'left',
        label: this.$t('registries.unloadingList.sign'),
        field: 'sign',
        name: 'sign',
        required: true,
        sortable: false,
      },
    ];
  }

  created(): void {
    this.init();
  }

  search(query: SearchQuery): void {
    this.searchQuery = query;
    this.updateTableData();
  }

  async updateTableData(val?: any): Promise<void> {
    this.tableLoading = true;
    const query = [];

    if (typeof this.searchQuery !== 'undefined') {
      this.queryString = this.searchQuery?.query || '';
      this.fulltextString = this.searchQuery?.fulltext || '';
    }

    if (this.queryString) {
      query.push(`${this.queryString}`);
    }
    try {
      const registryApi = new RegistryApi();
      const { data } = await registryApi.pagingRegistry(
        val?.pagination?.page ?? this.pagination.page,
        val?.pagination?.rowsPerPage ?? this.pagination.rowsPerPage,
        query.join(' and '),
        this.fulltextString,
        val?.pagination.sortBy || this.pagination.sortBy
          ? `${
              val?.pagination.descending || this.pagination.descending
                ? '-'
                : '+'
            }${val?.pagination.sortBy ?? this.pagination.sortBy}`
          : ''
      );

      this.pagination.rowsNumber = data.totalRows || 0;
      this.pagination.page = data.page;
      this.pagination.rowsPerPage = data.perPage;

      this.data = data.records || [];
    } catch (e) {
      notifyError(
        this.$t('registries.unloadingList.noRecordsFound').toString()
      );
      console.warn(`failed count ${e}`);
    } finally {
      this.tableLoading = false;
    }
  }

  async exportRecords(): Promise<void> {
    this.loading = true;

    if (!this.selected.length) {
      notifyError('Нет выбранных объектов для скачивания');
      this.loading = false;
      return;
    }

    const records = this.selected;
    const registryApi = new RegistryApi();

    for (const record of records) {
      const { request } = await registryApi.getRegistry(record.id);
      const archiveUrl = request.responseURL;
      const response = await axios.get(archiveUrl, {
        responseType: 'arraybuffer',
      });
      const blob = new Blob([response.data], { type: 'octet/stream' });
      saveAs(blob, `${record.title}.zip`);
    }

    this.loading = false;
  }

  exportRecordsByIds(): void {
    this.loading = true;

    const query = [];

    if (typeof this.searchQuery !== 'undefined') {
      this.queryString = this.searchQuery?.query || '';
      this.fulltextString = this.searchQuery?.fulltext || '';
    }

    if (this.queryString) {
      query.push(`${this.queryString}`);
    }

    this.$store
      .dispatch('wf/processes/dispatchProcess', {
        processKey: 'ExportElsCompencationCreateUploading',
        userId: this.$store.getters['oidcClient/currentUser'].sub,
        data: {
          registryCode: CHILDRENS_REST_CASHBACK_CODE,
          query: query.join(' and '),
          fulltext: this.fulltextString,
        },
      })
      .then(({ traceId }) => {
        const handler = (e: any) => {
          const data = JSON.parse(get(e, 'data', '{}'));

          if (data.traceId === traceId) {
            this.loading = false;

            if (data.body?.url) {
              S3UrlSignerFilesService.fetchFileFromS3ByUrl({
                url: data.body.url,
              }).then(({ file }) => {
                saveAs(
                  file,
                  `${this.$t('registries.unloadingList.title')}.xls`
                );
                notifySuccess(
                  'xls файл успешно выгружен',
                  'check_circle_outline'
                );
              });
            } else if (!data.body?.success) {
              notifyError(`Ошибка экспорта: ${data.body.description || ''}`);
            }
          }
        };
        this.$websockets.addListener(handler);
      });
  }

  GenerateAnOrder(): void {
    this.loading = true;
    this.$store
      .dispatch('wf/processes/dispatchProcess', {
        processKey: CHILDRENS_REST_CASHBACK_UPLOADING_PROCESS__CODE,
      })
      .then(({ traceId }) => {
        const handler = (e: any) => {
          const data = JSON.parse(get(e, 'data', '{}'));
          if (data.traceId === traceId) {
            this.loading = false;
            const outData = get(data, 'body.userTask.outData', null);
            const taskId = get(data, 'body.userTask.taskId', '');
            if (outData && outData.success) {
              this.$websockets.removeListener(handler);
              this.addSign({}, { taskId, traceId, success: false });
            }
          }
        };
        this.$websockets.addListener(handler);
      });
  }

  importUFK(): void {
    this.uploadModal = true;
  }

  selectionHandler(
    selection: Array<ExportRegistryKompensDetskOtdMIR>
  ): void {
    this.selected = selection.filter(
      // TODO: openapi атрибут cancelDate пока не добавлен в сваггер.
      // как только добавят надо перегенерировать api и вернуть элементу тип ExportRegistryKompensDetskOtdMIR
      (item: any) => item.signed || item.cancelDate
    );
  }

  addSign(item: any, process?: Prosess): void {
    this.currentProcess = process || null;
    this.currentItem = item;
    this.signModal = true;
  }

  annulInfo(item: ExportRegistryKompensDetskOtdMIR): void {
    this.currentItem = item;
    this.annulInfoModal = true;
  }

  getSignInfo(item: ExportRegistryKompensDetskOtdMIR): void {
    this.currentItem = item;
    this.signInfoModal = true;
  }

  async init(): Promise<void> {
    await this.updateTableData();
  }

  async fetchDocumentAttachment(document: any) {
    const fileName =
      document?.title ?? this.$t('registries.unnamed').toString();
    const url = document?.reportLink;

    if (url) {
      try {
        const { file } = await S3UrlSignerFilesService.fetchFileFromS3ByUrl({
          url: url,
        });

        saveAs(file, `${fileName}.pdf`);
      } catch (e) {
        notifyError(e.message.toString());
      }
    }
  }
}

declare interface Prosess {
  taskId: string;
  traceId: string;
  success: boolean;
}
</script>
