<i18n>
{
  "en": {
    "reports": {
      "CommonCard": {
        "report": "Report",
        "stopped": "Automatic report generation completed {date}<br>Responsible person: {fullname}",
        "stop": "Stop automatic generation",
        "stopShort": "Stop generation",
        "stopDate": "Automatic generation end date",
        "stopUser": "User"
      }
    }
  },
  "ru": {
    "reports": {
      "CommonCard": {
        "report": "Отчет",
        "stopped": "Автоматическая генерация отчета завершена {date}<br>Ответсветственный: {fullname}",
        "stop": "Остановить автоматическую генерацию",
        "stopShort": "Завершить генерацию",
        "stopDate": "Дата завершения автоматической генерации",
        "duplicate": "Дублировать",
        "duplicateTooltip": "Создать новый отчет используя текущие параметры",
        "stopUser": "Пользователь"
      }
    }
  }
}
</i18n>

<template>
  <div>
    <div
      class="flex justify-between items-center bg-white q-pa-md q-mt-md q-mx-md rounded-borders no-wrap"
    >
      <q-btn
        padding="xs"
        class="text-grey-7 q-mr-md"
        color="grey-3"
        icon="arrow_back"
        @click="goToReports"
      />
      <div
        class="column justify-center text-h5 q-mr-auto"
        style="min-height: 36px"
      >
        <div style="display: flex" class="items-center">
          {{ get(model, 'number') }} {{ get(model, 'name') }}
        </div>
      </div>
      <div class="row">
        <div v-if="get(model, 'auto.enabled')">
          <q-btn
            class="q-ml-sm"
            outline
            :label="$t('reports.CommonCard.stopShort')"
            @click="stop"
          >
            <q-tooltip>
              {{ $t('reports.CommonCard.stop') }}
            </q-tooltip>
          </q-btn>
        </div>
        <div>
          <q-btn
            class="q-ml-md"
            outline
            :label="$t('reports.CommonCard.duplicate')"
            color="primary" 
            @click="create = true"
            :loading="isCreating"
          >
            <report-create
              v-if="create"
              v-model="create"
              :base-report="baseReport"
              @creating="creating"
              :defaultParams="params"
            />
            <q-tooltip>
              {{ $t('reports.CommonCard.duplicateTooltip') }}
            </q-tooltip>
          </q-btn>
        </div>
      </div>
    </div>
    <div
      class="q-gutter-y-md row bg-white q-px-lg q-pb-md q-pt-sm q-mt-md q-mx-md rounded-borders"
    >
      <div class="col text-primary q-pa-sm">
        <div class="q-gutter-y-md">
          <base-label-value
            v-for="{ label, value } in columnList"
            :key="label"
            :loading="loading"
          >
            <template #label>
              {{ $t(label) }}
            </template>
            <template #value>
              <q-expansion-item
                v-if="value.length > 100"
                :label="longLabel(value)"
                header-class="text-primary"
                style="margin-left: -16px"
              >
                <q-card>
                  <q-card-section>
                    {{ value }}
                  </q-card-section>
                </q-card>
              </q-expansion-item>
              <span v-else>
                {{ value }}
              </span>
            </template>
          </base-label-value>
        </div>
      </div>
    </div>
    <div
      class="q-gutter-y-md row bg-white q-px-lg q-pb-md q-pt-sm q-mt-md q-mx-md rounded-borders"
    >
      <q-table
        :loading="attachments.loading"
        class="no-shadow text-grey-7 full-width"
        row-key="name"
        :columns="columnsAttachments"
        :visible-columns="visibleColumnsAttachments"
        :data="attachments.records"
        wrap-cells
        :pagination.sync="attachments.pagination"
        @request="initResults"
      >
        <template #body-cell-download="props">
          <q-td :props="props">
            <q-btn
              flat
              dense
              icon="arrow_downward"
              size="16"
              style="color: rgba(0, 0, 0, 0.54)"
              color="primary"
              @click="fetchAttachment(props.row)"
            >
              <q-tooltip>
                {{ $t('reports.columns.downloadSingle') }}
              </q-tooltip>
            </q-btn>
          </q-td>
        </template>
      </q-table>
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
import ReportCreate from '../../reports/create/index.vue';
import { saveAs } from 'file-saver';
import { convertDateFormatWithoutLocale } from '@utils/format-date';
import { DateFormat } from '@constants/utils/format-date';
import { notifyError } from '@utils/notify';
import S3UrlSignerFilesService from '@services/s3urlsigner/files';
import { CardNeedToUpdateType } from '@constants/models/Card';
import get from 'lodash/get';
import has from 'lodash/has';
import { DocumentApi } from '@openapi/document-registry';
import {
  fetchAttachmentReport,
  fetchBaseReport,
  fetchReportsByParams,
} from '@services/document-registry';

const documentApi = new DocumentApi();

@Component({
  components: {
    ReportCreate,
  },
  methods: {
    get,
  },
})
export default class ReportCard extends Vue {
  @Prop() protected common!: any;
  @Prop() protected model: any;
  @Prop() protected userTask: any;

  baseReport: any = null;
  buttons = [];
  components: Record<string, any> = {};
  regions = [];
  regionsFilter = [];
  availableDocumentTypeOptions = [];
  documentTypeOptions = [];
  disableAllButtons = false;
  upload = {};
  create = false;
  isCreating = false;
  updates = {};
  tabs = {
    current: this.common.active,
    list: [],
  };

  private columns = [
    {
      field: 'name',
      label: 'reports.columns.name',
      name: 'name',
    },
    {
      label: 'reports.columns.number',
      field: 'number',
      name: 'id',
      required: true,
    },
    {
      field: 'params.regions',
      label: 'reports.columns.region',
      name: 'region',
      format: (regions: { name: string }[]) =>
        regions ? regions.map(({ name }) => name).join(', ') : '',
    },
    {
      field: 'params.services',
      label: 'reports.columns.serviceName',
      name: 'services',
      format: (services: { fullName: string }[]) =>
        services ? services.map(({ fullName }) => fullName).join(', ') : '',
    },
    {
      field: 'params.organizations',
      label: 'reports.columns.organization',
      name: 'organization',
      format: (regions: { fullname: string }[]) =>
        regions ? regions.map(({ fullname }) => fullname).join(', ') : '',
    },
    {
      field: 'params.accounts',
      label: 'reports.columns.accounts',
      name: 'account',
      format: (regions: { fullname: string }[]) =>
        regions ? regions.map(({ fullname }) => fullname).join(', ') : '',
      sortable: false,
    },
    {
      field: 'startDate',
      format: (val: Date) => {
        if (val) {
          return convertDateFormatWithoutLocale(val);
        }
        return '';
      },
      label: 'reports.columns.startDate',
      name: 'startDate',
    },
    {
      field: 'auto.period',
      label: 'reports.columns.period',
      name: 'auto.period',
    },
    {
      field: 'auto.stopped.date',
      format: (val: Date) => {
        if (val) {
          return convertDateFormatWithoutLocale(val);
        }
        return '';
      },
      label: 'reports.CommonCard.stopDate',
      name: 'stopDate',
      required: true,
    },
    {
      field: 'auto.stopped.fullname',
      label: 'reports.CommonCard.stopUser',
      name: 'stopUser',
      required: true,
    },
  ];

  attachments: reportAttachments = {
    pagination: {
      descending: true,
      rowsPerPage: 10,
      sortBy: '',
      rowsNumber: 0,
      page: 1,
    },
    records: [],
    loading: true,
  };

  private get stopped() {
    const stopped = get(this.model, 'auto.stopped');

    if (!stopped) {
      return false;
    }

    return {
      ...stopped,
      date: convertDateFormatWithoutLocale(stopped.date),
    };
  }

  private get visibleColums() {
    return (
      (this.baseReport &&
        this.baseReport.columns &&
        this.baseReport.columns.card) ||
      []
    );
  }

  private get visibleColumnsAttachments() {
    return (
      (this.baseReport &&
        this.baseReport.columns &&
        this.baseReport.columns.attachments) ||
      []
    );
  }

  private get columnsAttachments() {
    return [
      {
        label: this.$t('reports.columns.n'),
        field: 'number',
        name: 'id',
        align: 'left',
        sortable: true,
      },
      {
        align: 'left',
        field: 'user',
        label: this.$t('reports.columns.user'),
        name: 'user',
        sortable: true,
      },
      {
        align: 'left',
        field: 'serviceName',
        label: this.$t('reports.columns.serviceName'),
        name: 'serviceName',
        sortable: true,
      },
      {
        align: 'left',
        field: 'organizationName',
        label: this.$t('reports.columns.organizationName'),
        name: 'organizationName',
        sortable: true,
      },
      {
        align: 'left',
        field: 'date',
        format: (val: string) => {
          if (val) {
            return convertDateFormatWithoutLocale(val);
          }
          return '';
        },
        label: this.$t('reports.columns.date'),
        name: 'date',
        sortable: true,
      },
      {
        align: 'left',
        field: (v: any) => get(v, 'params.range'),
        label: this.$t('reports.columns.range'),
        style: 'white-space: nowrap',
        name: 'range',
        format: (range: { from: string; to: string }) => {
          if (!range) {
            return '';
          }
          const { from, to } = range;
          const convert = convertDateFormatWithoutLocale;
          const toFormat = DateFormat.datetime;

          if (from && to) {
            return `${convert(from, toFormat)} - ${convert(to, toFormat)}`;
          } else if (from) {
            return `${this.$t('base.dateRange.from')} ${convert(
              from,
              toFormat
            )}`;
          } else if (to) {
            return `${this.$t('base.dateRange.to')} ${convert(to, toFormat)}`;
          }

          return '';
        },
        sortable: false,
      },
      {
        align: 'left',
        field: 'count',
        label: this.$t('reports.columns.count'),
        name: 'count',
        sortable: true,
      },
      {
        align: 'left',
        field: 'attachments',
        label: this.$t('reports.columns.action'),
        style: 'text-align: center; width: 4em',
        name: 'download',
        required: true,
      },
    ];
  }

  private get columnList() {
    const visibleColums = this.visibleColums;
    return this.columns
      .filter(({ name, required }) => required || visibleColums.includes(name))
      .map(({ label, format, field }) => {
        let value = get(this.model, field);
        if (format) {
          value = format(value);
        }
        return {
          label,
          value,
        };
      })
      .filter(({ value }) => value !== undefined && value !== '');
  }

  private get loading() {
    return !this.model && !this.components;
  }

  private get commonData() {
    return get(this.common, 'models.index.data', []);
  }

  private get currentUser() {
    return this.$store.getters['oidcClient/currentUser'] || null;
  }

  private get params() {
    return get(this.model, 'params', []);
  }

  @Watch('common.active')
  activeTab(val: string): void {
    this.tabs.current = val;
  }

  @Watch('common.needToUpdate', { immediate: true })
  handler(val: CardNeedToUpdateType): void {
    this.$store.commit(`utils/cards/needToUpdate`, CardNeedToUpdateType.FALSE);
    this.init(val);
  }

  created() {
    this.init();
  }

  beforeDestroy() {
    this.$store.commit(`utils/cards/removeModel`, {
      path: this.common.path,
    });

    this.$store.commit(`utils/cards/removeUserTask`, {
      path: this.common.path,
    });
  }

  init(needToUpdateType = CardNeedToUpdateType.TRUE) {
    if (needToUpdateType !== CardNeedToUpdateType.FALSE) {
      this.initModel().then(this.initBaseReport).then(this.initResults);
    }
  }

  initModel() {
    return new Promise((resolve, reject) => {
      try {
        documentApi
          .getDocument('StatReport', this.common.id)
          .then(({ data: model }) => {
            this.$store.commit(`utils/cards/addModel`, {
              model,
              path: this.common.path,
            });
            return resolve();
          })
          .catch((e) => reject(e));
      } catch (e) {
        return reject(e);
      }
    });
  }

  initBaseReport() {
    if (this.$route.params.parent) {
      return (this.baseReport = this.$route.params.parent);
    }
    fetchBaseReport(this.model.parentId).then(
      (baseReport) => (this.baseReport = baseReport)
    );
  }

  initResults(val: any) {
    if (val && val.pagination) {
      this.attachments.pagination.descending = val.pagination.descending;
      this.attachments.pagination.rowsPerPage = val.pagination.rowsPerPage;
      this.attachments.pagination.sortBy = val.pagination.sortBy;
      this.attachments.pagination.page = val.pagination.page;
    }

    return this.fetch();
  }

  stop() {
    const user = this.currentUser || {};

    const names = ['family_name', 'given_name[0]', 'middle_name[0]']
      .map((e) => get(user, e))
      .filter(Boolean);

    for (let i = names.length; --i > 0; ) {
      names[i] += '.';
    }
    return documentApi
      .updateDocument('StatReport', [
        {
          ...this.model,
          auto: {
            ...this.model.auto,
            enabled: false,
            stopped: {
              date: new Date().toISOString(),
              id: user.id,
              fullname: names.join(' '),
            },
          },
        },
      ])
      .then(() => {
        this.init();
      });
  }

  fetch() {
    this.attachments.loading = true;

    fetchReportsByParams({ reportId: this.common.id })
      .then(({ data: reportArr }) => {
        const report = reportArr[0];
        // this.attachments.pagination.rowsNumber = undefined;
        this.attachments.records = report.StatReportResult
          ? [
              {
                ...report.StatReportResult,
                id: report.StatReportResult?._key,
                attachments: report.DocumentAttachmentFileDescriptor
                  ? [
                      {
                        ...report.DocumentAttachmentFileDescriptor,
                        id: report.DocumentAttachmentFileDescriptor?._key,
                      },
                    ]
                  : [
                      {
                        s3uri: report.StatReport.s3uri,
                        s3filename: report.StatReport.s3filename,
                      },
                    ],
              },
            ]
          : [];
      })
      .catch((e) => {
        notifyError(e.message.toString());
      })
      .finally(() => (this.attachments.loading = false));
  }

  fetchAttachment(document: any): void {
    this.$set(document, 'loading', true);
    const attachment = get(document, 'attachments[0]');

    const file = attachment.s3uri && attachment;
    if (file) {
      S3UrlSignerFilesService.fetchFileFromS3ByUrl({
        url: file.s3uri,
      })
        .then((result) => {
          saveAs(result.file, file.s3filename);
        })
        .catch((e) => {
          notifyError(e.message.toString());
        });
    } else if (attachment) {
      fetchAttachmentReport(
        'StatReportResult',
        document.id,
        attachment.fileName
      )
        .then((result) => saveAs(result.file, attachment.fileName))
        .catch((e) => notifyError(e.message.toString()))
        // eslint-disable-next-line no-param-reassign
        .finally(() => (document.loading = false));
    } else {
      // eslint-disable-next-line no-param-reassign
      document.loading = false;
      return notifyError(
        this.$t('DocumentsCard.documentFileUrlIsEmpty').toString()
      );
    }
  }

  fetchCards(): void {
    const componentsObj = this.components ? this.components : {};

    this.buttons.forEach((button) => {
      const pathComponent = get(button, 'componentPath');

      if (!pathComponent || get(this.components, `${pathComponent}`)) {
        return;
      } // не выполняем загрузку, если нет pathComponent или уже загружено
      // todo refactor
      componentsObj[pathComponent] = {};
      this.$set(
        componentsObj,
        pathComponent,
        this.$GlobalComponentImporter.registerComponent(
          pathComponent,
          `cards/reports/`
        )
      );
    });
    this.components = componentsObj;
  }

  goToReports(): void {
    this.$router.push({
      path: `/reports${this.model ? `/${this.model.parentId || 1}` : ''}`,
      query: {
        auto: has(this.model, 'auto.enabled') ? 'true' : 'false',
        savedSearch: 'true',
      },
    });
  }

  longLabel(label: string): string {
    const orgArray = label
      .split(',')
      .map((el: string) => el.trim().replace(/^"|"$/g, ''));
    return (
      orgArray.slice(0, 2).join(', ') + '...' + ' всего: ' + orgArray.length
    );
  }

  creating(promise: Promise<any>): void {
    this.isCreating = true;
    promise
      .then(() => {
        return this.goToReports();
      })
      .finally(() => (this.isCreating = false));
  }
}

type reportAttachments = {
  pagination: {
    descending: boolean;
    rowsPerPage: number;
    sortBy: string;
    rowsNumber: number;
    page: number;
  };
  records: Record<string, unknown>[];
  loading: boolean;
};

</script>
