<template>
  <div v-if="isActive" class="q-pb-md">
    <q-card class="no-shadow q-gutter-y-md q-mx-md no-border-radius">
      <div class="q-mx-md q-pt-md q-pa-sm">
        <div class="q-gutter-y-md q-mb-md">
          <q-table
            v-if="!loading"
            class="no-shadow text-grey-9"
            row-key="id"
            :columns="columns"
            :data="tableData"
            :rows-per-page-options="[10, 20, 50]"
            :pagination.sync="pagination"
            wrap-cells
            @request="init"
          >
            <template v-slot:body="props">
              <q-tr :props="props">
                <q-td key="applicationNumber" :props="props">
                  <q-chip
                    clickable
                    @click="
                      openCard(props.row.application.id, 'statements', 'author')
                    "
                  >
                    {{ props.row.application.orderId }}
                  </q-chip>
                </q-td>
                <q-td key="applicationName" :props="props">
                  {{ props.row.application.name }}
                </q-td>
                <q-td key="applicationRegistrationDate" :props="props">
                  {{ displayDate(props.row.application.date) }}
                </q-td>
                <q-td key="organizationName" :props="props">
                  {{ props.row.organizationName }}
                </q-td>
                <q-td key="resolution" :props="props">
                  <div
                    v-for="resolution in getResolutionsByOrdeid(
                      props.row.application.orderId
                    )"
                    :key="resolution && resolution.number"
                  >
                    <span v-if="resolution">
                      {{ displayDate(resolution.finishDate) }}
                    </span>
                    <q-chip
                      v-if="resolution"
                      clickable
                      @click="
                        openRegistryCard(
                          //
                          resolution.id,
                          resolution.registryCode
                        )
                      "
                    >
                      {{ resolution.number }}
                    </q-chip>
                  </div>
                  <q-skeleton v-if="resolutionLoading" type="text" />
                </q-td>
              </q-tr>
            </template>
          </q-table>
        </div>
      </div>
    </q-card>
  </div>
</template>

<script lang="ts">
import Vue from 'vue';
import { Component, Watch, Prop } from 'vue-property-decorator';
import { BaseCardCommon, TableColumn } from '@/interfaces';
import {
  DocumentApi,
  Document as Application,
} from '@openapi/document-registry';
import {
  RegistryMapping,
  RegistryMappingApi,
  RegistryApi,
} from '@openapi/registry-service';
import {
  DocumentApi as RegistryDocumentApi,
  Document as RegistryDocument,
} from '@openapi/registry-data';
import get from 'lodash/get';
import { convertDateFromBackendFormat, DateFormat } from '@/utils/format-date';
import camelCase from 'lodash/camelCase';
import type { ExtendedPerson } from '@interfaces/services/personal-accounts';
import { notifyError } from '@/utils/notify';
import { TablePagination } from '@/models/base/TablePagination';
import isEmpty from 'lodash/isEmpty';
import { isArray } from 'lodash';

const documentApi = new DocumentApi();

interface Resolution {
  id: string;
  number?: string;
  finishDate?: string;
  registryCode?: string;
}

type Timestemp = number;

interface AttachedDocument {
  schema: 'AttachedDocuments';
  DataGISGMPApprovedInvertLabel: string;
  file: {
    digest: string;
    hash: string;
    code: string;
    name: string;
    type: string;
    url: string;
  };
  template: {
    name: string;
    url: string;
  };
  sign: {
    certificate: {
      issuerName: string;
      subjectName: string;
    };
    name: string;
    url: string;
  };
  modified: Timestemp;
  id: string;
  source: string;
  type: {
    code: string;
    name: string;
  };
  DataIsMvdLiveApprovedInvertLabel: string;
  number: string;

  resDopInformation: string;
  generated: true;
  digest: string;
  resReqDate: string;
  s3url: string;
  goal: number;
  resServProvisRufusal: boolean;
  resFalsedDocs: boolean;
  resNumber: string;
  resReqNumber: number;
  name: string;
  resDate: string;
  resNoPaymentInfo: boolean;
}

interface Subject {
  schema: 'Subject';
  lastName: string;
  address: {
    postal: {
      text: string;
    };
    register: {
      text: string;
    };
  };
  gender: number;
  documents: [
    {
      number: string;
      series: string;
      name: string;
      issueIdCode: number;
      issueDate: string;
      type: string;
      issueOrg: string;
    }
  ];
  citizenship: string;
  fullName: string;
  firstName: string;
  phone: string;
  modified: number;
  isApplicantUl: false;
  middleName: string;
  id: string;
  dateBirth: string;
  snils: string;
  email: string;
}
interface RegistryRegisSmohMash {
  id: string;
  modified: Timestemp;
  schema: string;
  allDocuments: AttachedDocument[];
  serviceFullName: string;
  orderId: number;
  customFields: {
    prototype: false;
  };
  departmentId: string;
  document: AttachedDocument;
  applicationRegNumber: string;
  assigneeId: string;
  applicant: Subject;
  Goal: number;
  assigneeFullName: string;
  finishSignDate: string;
  departmentFullName: string;
  statement: {
    gettingResults: {
      isPaperDocumentRequired: boolean;
      methodGettingResults: number;
    };
    goal: number;
    data: {
      vehiclePasport: {
        number: number;
        series: string;
      };
      vehicleData: {
        axleNumber: string[];
        color: string;
        year: number;
        engineNumber: number[];
        flashing: string;
        vehicleNumber: number;
        brand: string;
        gearboxNumber: string;
        nameVehicle: string;
      };
      osagoDetails: {
        number: number;
        series: string;
      };
    };
    workDays: number;
    competentOrganizationId: number;
    variantChoice: Record<string, number>;
    methodGettingResults: {
      isPaperDocumentRequired: boolean;
      methodGettingResults: number;
    };
    formTarget: {
      name: string;
      id: number;
    };
    otherRecipientData: Record<string, number>;
    competentOrganizationName: string;
  };
  finishDate: string;
  applicationId: string;
  applicationSystem: {
    decision: {
      code: string;
    };
    currentDivision: {
      fullName: string;
      id: string;
    };
    fullName: string;
    applicant: {
      fullName: string;
      id: string;
    };
    interDepReqPrinted: boolean;
    regionCode: string;
    processId: string;
    regionId: string;
    avaliable: boolean;
    service: string;
    startDateIso: string;
    orderStatusCode: string;
    department: {
      fullName: string;
      id: string;
    };
    serviceId: string;
    shortName: string;
    startDate: string;
    status: {
      external: string;
      internal: string;
      system: string;
    };
  };
  signer: {
    fullName: string;
    id: string;
  };
  status: {
    external: string;
    internal: string;
    system: string;
  };
}

interface ApplicationAndResolution {
  application: {
    id: string;
    orderId: string;
    name: string;
    date: string;
  };
  organizationName: string;
}

interface ResolutionRegistryDocument extends RegistryDocument {
  finishDate?: string;
  applicationRegNumber?: string;
  orderId?: string;
  document?: {
    resNumber: string;
  };
}

function searchByFieldInList(field: string, list: string[]): string {
  list = list.map((s) => `'${s}'`);
  return `${field} =in= (${list.join(',')})`;
}

@Component({
  components: {},
})
export default class Statements extends Vue {
  @Prop({}) private common?: BaseCardCommon;
  @Prop({}) private model?: ExtendedPerson;

  loading = false;
  activated = false;
  resolutionLoading = false;
  applications: Application[] = [];
  tableData: ApplicationAndResolution[] = [];
  resolutionsIndex: Record<string, Resolution[]> = {};

  get columns(): TableColumn[] {
    return [
      {
        align: 'left',
        label: 'Номер заявления',
        name: 'applicationNumber',
        style: 'white-space: normal;',
        required: true,
        sortable: false,
      },
      {
        align: 'left',
        label: 'Название услуги',
        name: 'applicationName',
        style: 'white-space: normal;',
        required: true,
        sortable: false,
      },
      {
        align: 'left',
        label: 'Дата обращения',
        name: 'applicationRegistrationDate',
        style: 'white-space: normal;',
        required: true,
        sortable: false,
      },
      {
        align: 'left',
        label: 'Уполномоченный орган',
        name: 'organizationName',
        style: 'white-space: normal;',
        required: true,
        sortable: false,
      },
      {
        align: 'left',
        label: 'Решения',
        name: 'resolution',
        style: 'white-space: normal;',
        required: true,
        sortable: false,
      },
    ];
  }

  pagination: TablePagination = {
    page: 1,
    descending: false,
    rowsPerPage: 10,
    rowsNumber: 0,
    sortBy: 'applicationRegistrationDate',
  };

  get applicationIds(): string[] {
    const rowsPerPage = this.pagination?.rowsPerPage || 0;
    const page = this.pagination?.page - 1 || 0;
    const ids = (this.model?.personapplication || [])?.flatMap(
      ({ applicationUUID }) => applicationUUID || []
    );
    const shift = page * rowsPerPage;

    return ids?.slice(shift, shift + rowsPerPage);
  }

  get orderIds(): string[] {
    return this.applications.map((app) => {
      return get(app, 'common.orderId', '');
    });
  }

  @Watch('model.personapplication', { immediate: true })
  onChangeApplicationIds(ids: string[]): void {
    if (!ids?.length || !this.isActive) return;
    this.init();
  }

  @Watch('common.active', { immediate: true })
  onChangeActiveModule(activeModule: string): void {
    if (this.activated || !this.model?.personapplication?.length) return;
    if (activeModule === 'statements') {
      this.init();
      this.activated = true;
    }
  }

  get isActive(): boolean {
    return this.common?.active === 'statements';
  }

  openCard(
    id: string,
    path: string,
    def: string,
    query: Record<string, string> = {}
  ): void {
    this.$router.push({
      name: 'cards',
      params: {
        id: id,
        path: path,
      },
      query: {
        components: this.$store.getters[
          `cardComponents/${camelCase(path)}/components`
        ],
        active: def,
        ...query,
      },
    });
  }

  async openRegistryCard(
    resolutionId: string,
    registryCode?: string
  ): Promise<void> {
    const api = new RegistryApi();
    const {
      data: [registry],
    } = await api.searchRegistry(`code=='${registryCode}'`);
    if (!(registry && registryCode)) {
      notifyError('Не удалось открыть карточку распоряжения');
      if (!registryCode) notifyError('Отсутствует код реестра');
      if (!registry) {
        notifyError(`Не удалось найти реестр ${registryCode}`);
        console.error(`Реестр решений  ${registryCode} не найден`);
      }
      return;
    }
    this.openCard(resolutionId, 'registry-object', 'data', {
      reg: registryCode,
      regid: registry.id,
    });
  }

  displayDate(date?: string): string {
    return date ? convertDateFromBackendFormat(date, DateFormat.date) : '';
  }

  getResolutionsByOrdeid(orderId: string): Resolution[] {
    return this.resolutionsIndex[orderId] || [];
  }

  async loadResolutions(): Promise<void> {
    const serviceIds = new Set<string>();
    const registryCodes = new Set<string>();
    this.applications.forEach((appalcation) => {
      serviceIds.add(get(appalcation, 'system.serviceId') || get(appalcation, 'statement.serviceId'));
    }, {});
    this.resolutionsIndex = {};
    try {
      const registryMappingApi = new RegistryMappingApi();
      const registryDocumentApi = new RegistryDocumentApi();
      const { data: mapping } = await registryMappingApi.searchRegistryMapping(
        searchByFieldInList('serviceId', [...serviceIds])
      );
      mapping.forEach(({ registryCode }) => {
        registryCodes.add(registryCode);
      }, {});

      const resolutionsByApp = await Promise.all(
        [...registryCodes].map(async (registryCode) => {
          const { data } = await registryDocumentApi.searchDocuments(
            registryCode,
            searchByFieldInList('orderId', this.orderIds)
          );
          return data as ResolutionRegistryDocument[];
        })
      );
      resolutionsByApp
        .flatMap((resolutions) => resolutions)
        .forEach((resolution) => {
          const resNumber = resolution.document?.resNumber;
          const {
            id,
            finishDate,
            schema: registryCode,
            applicationRegNumber,
            orderId = '',
          } = resolution;

          if (!isArray(this.resolutionsIndex[orderId])) {
            this.resolutionsIndex[orderId] = [];
          }

          this.resolutionsIndex[orderId].push({
            id,
            finishDate,
            registryCode,
            number: resNumber || applicationRegNumber,
          });
        });
    } catch (error) {
      console.warn(
        `[perconal-accounts/statements] Couldn't get list of Resolutions`
      );
    }
    this.resolutionLoading = false;
  }

  async init({ pagination }: { pagination?: TablePagination } = {}): Promise<void> {
    this.pagination.rowsNumber = this.model?.personapplication?.length || 0;
    if (pagination) {
      this.pagination = {
        ...pagination,
      };
    }
    if (isEmpty(this.applicationIds)) return;

    this.loading = true;
    this.resolutionLoading = true;
    try {
      const { data } = await documentApi.searchDocuments(
        'Applications',
        searchByFieldInList('id', this.applicationIds)
      );
      this.applications = data;
      this.tableData = [];
      data.forEach((application) => {
        const orderId = String(get(application, 'common.orderId'));
        const row = {
          application: {
            id: get(application, 'id'),
            orderId: orderId,
            name: get(application, 'system.shortName'),
            date: get(application, 'common.registrationDate'),
          },
          organizationName:
            get(application, 'system.department.shortName', '') ||
            get(application, 'system.department.fullName', ''),
        };
        this.tableData.push(row);
      });
      this.loadResolutions();
    } catch (error) {
      console.warn(
        `[perconal-accounts/statements] Couldn't get list of appalcations`
      );
    }
    this.loading = false;
  }
}
</script>
