<template>
  <div class="row q-col-gutter-x-md">
    <div class="content" :class="isFileUploaded ? 'col-4' : 'col-8'">
      <q-card class="q-pa-md no-shadow column no-wrap content">
        <span class="text-h6">{{
          $t('services.emulation.serviceXmlFile')
        }}</span>
        <q-separator />
        <div class="q-col-gutter-y-md q-mt-none">
          <q-uploader
            ref="xmlUploaderRef"
            class="q-pt-md no-shadow"
            style="width: auto; max-width: 320px"
            url="http://localhost:4444/upload"
            accept=".xml"
            @rejected="onRejected"
            @added="onAdded"
            @removed="onRemoved"
          >
            <template v-slot:header="scope">
              <div class="row no-wrap items-center q-pa-sm q-gutter-xs">
                <q-btn
                  v-if="scope.uploadedFiles.length > 0"
                  icon="done_all"
                  @click="scope.removeUploadedFiles"
                  round
                  dense
                  flat
                >
                  <q-tooltip>Remove Uploaded Files</q-tooltip>
                </q-btn>
                <q-spinner
                  v-if="scope.isUploading"
                  class="q-uploader__spinner"
                />
                <div class="col">
                  <div class="q-uploader__title">
                    {{ $t('services.emulation.selectFile') }}
                  </div>
                  <div class="q-uploader__subtitle">
                    {{ scope.uploadSizeLabel }} /
                    {{ scope.uploadProgressLabel }}
                  </div>
                </div>
                <q-btn
                  v-if="scope.canAddFiles"
                  type="a"
                  icon="add_box"
                  round
                  dense
                  flat
                >
                  <q-uploader-add-trigger />
                  <q-tooltip>{{ $t('services.emulation.pickFile') }}</q-tooltip>
                </q-btn>
                <q-btn
                  v-if="scope.isUploading"
                  icon="clear"
                  @click="scope.abort"
                  round
                  dense
                  flat
                >
                  <q-tooltip>Abort Upload</q-tooltip>
                </q-btn>
              </div>
            </template>
          </q-uploader>
          <template v-if="isFileAdded">
            <codemirror
              :key="'' + isCurrentTabOpen + isFileUploaded"
              class="full-width"
              :class="{ 'non-selectable': isFileUploaded }"
              :value="xml"
              :options="cmOptions"
              :disabled="uploadDisabled"
              @input="onCmCodeChange"
            />

            <div class="row items-center">
              <span v-if="xsd">
                {{ $t('services.emulation.validateBySchema') }}
              </span>
              <add-file-button
                :title="$t('services.emulation.validate')"
                :disable="uploadDisabled"
                extensions=".xsd"
                @added="(file) => (xsd = file)"
              />
            </div>

            <div>
              <q-btn
                color="primary"
                filled
                :label="this.$t('services.emulation.uploadDocuments')"
                :disable="uploadDisabled"
                :loading="serviceLoading"
                @click="getOverlappingServiceDocuments"
              />
            </div>
            <template v-if="onUploadDocumentsClicked">
              <files-table
                v-if="documents.length"
                class="q-mb-md"
                :documents="documents"
                :title="$t('services.emulation.emulationProcessFiles')"
                :disable="uploadDisabled"
                @upload="onFilesUpload"
                @removed="onFilesRemoved"
              />
              <div v-else>
                <span>
                  {{ this.$t('services.emulation.documentsNotFound') }}
                </span>
              </div>
            </template>

            <steps
              :title="$t('services.emulation.selectEmulationSteps')"
              :disable="uploadDisabled"
              :current-step="beforeUploadStep"
              :has-process-started="false"
              @select="(v) => (beforeUploadStep = v)"
            />

            <div>
              <q-btn
                color="primary"
                filled
                :label="$t('services.emulation.start')"
                :disable="uploadDisabled"
                :loading="loading"
                @click="onUploadClick"
              />
            </div>
          </template>
        </div>
      </q-card>
    </div>

    <div :class="isFileUploaded ? 'col-8' : 'col-4'">
      <q-card class="content col-8 q-pa-md bg-grey-1 no-shadow column">
        <span class="text-h6">{{
          $t('services.emulation.emulationSetup')
        }}</span>
        <q-separator class="q-mb-md" />
        <no-file v-if="!isFileUploaded" />
        <template v-else>
          <validation-result :result="validationStatus" />

          <steps
            class="q-my-md"
            :current-step="step"
            :title="$t('services.emulation.emulationSteps')"
            :has-process-started="true"
            :has-interagencies-succeed="!!interagencies"
            :checks-loading="checksLoading"
            :interagencies-loading="interagenciesLoading"
            @get-checks="onGetChecksClick"
            @go-to-next-stage="getInteragencies"
            @get-interagencies="getInteragencies"
            @select="(v) => (step = v)"
          />

          <interdepartmental-requests-table
            v-if="interagencies"
            :row-interagencies="interagencies"
            :trace-id="mzTraceId"
            @interagencies-updated="
              (updatedInteragencies) => (interagencies = updatedInteragencies)
            "
          />

          <q-inner-loading :showing="interagenciesLoading" />
        </template>
      </q-card>
    </div>
  </div>
</template>

<script lang="ts">
// @ts-nocheck
import { codemirror } from 'vue-codemirror';
import 'codemirror/mode/xml/xml.js';
import 'codemirror/lib/codemirror.css';
import 'codemirror/addon/selection/active-line.js';
import Vue from 'vue';
import XmlParser from '@utils/parsers/XmlParser';
import intersectionWith from 'lodash/intersectionWith';
import get from 'lodash/get';
import Steps from '../components/steps.vue';
import FilesTable from '../components/files-table.vue';
import InterdepartmentalRequestsTable from '../components/interdepartmental-requests-table.vue';
import NoFile from '../components/no-file.vue';
import AddFileButton from '../components/add-file-button.vue';
import ValidationResult from '../components/validation-result.vue';
import { ServiceApi } from '@openapi/registry-service';
import { PetitionApi } from '@openapi/constructor-mz-mock-adapter';
import { DefaultApi } from '@openapi/cwf';
import {
  Document,
  ServiceWithDocuments,
  DocumentWithNameAndCode,
} from '../types.d';
import xmlConverter from 'xml-js';
import {
  consoleNotifyError,
  requestNotifyError,
  MIN_STEP,
} from '../utils';
import ValidationResult from '../components/validation-result.vue';
import { notifyError, notifySuccess } from '@/utils/notify';

const serviceApi = new ServiceApi();
const petitionApi = new PetitionApi();
const cwfApi = new DefaultApi();

export default Vue.extend({
  components: {
    codemirror,
    Steps,
    FilesTable,
    InterdepartmentalRequestsTable,
    NoFile,
    AddFileButton,
    ValidationResult,
    ValidationResult,
  },
  props: {
    isCurrentTabOpen: Boolean,
  },
  data() {
    return {
      documents: [] as Document[],
      interagencies: null as null | Object,
      serviceCard: null as null | Object,
      step: 1,
      beforeUploadStep: 1,
      traceId: '',
      mzTraceId: '',
      shouldValidate: false,
      cmOptions: {
        tabSize: 4,
        mode: 'text/html',
        styleActiveLine: true,
        lineNumbers: true,
        line: true,
        readOnly: false,
        disabled: false,
      },
      xml: '',
      isFileUploaded: false,
      xsd: '',
      validationStatus: null,
      isFileAdded: null,
      xmlFilename: '',
      loading: false,
      serviceLoading: false,
      interagenciesLoading: false,
      checksLoading: false,
      onUploadDocumentsClicked: false,
      s3Documents: [],
      serviceCard: null,
    };
  },
  computed: {
    uploadDisabled() {
      return this.isFileUploaded || this.loading || this.serviceLoading;
    },
  },
  methods: {
    onRejected(rejectedEntries: any) {
      consoleNotifyError(
        `${rejectedEntries.length} ${this.$t(
          'services.emulation.error.filesDidNotPass'
        )}`
      );
    },
    async onAdded(files: Array<File>) {
      this.xmlFilename = files[0].name;
      this.readXmlToEditor(files[0]);
    },
    async getOverlappingServiceDocuments() {
      this.serviceLoading = true;
      const json = await this.getServiceCard();
      this.serviceLoading = false;
      const serviceDocuments: DocumentWithNameAndCode[] = this.serviceCard
        ?.documents;
      const documents =
        get(json, 'tns:request.Documents') ||
        get(json, 'tns:request.tns:Documents');
      if (!documents) {
        consoleNotifyError(
          this.$t('services.emulation.error.noDocumentsInFile')
        );
        return;
      }
      const documentCodes = Object.keys(documents);
      documentCodes.forEach((dc, index) => {
        if (dc.startsWith('tns:')) {
          documentCodes[index] = dc.slice(4);
        }
      });
      this.documents = intersectionWith(
        serviceDocuments,
        documentCodes,
        (a, b) => a.code === b
      );
      this.onUploadDocumentsClicked = true;
    },
    async getServiceCard() {
      let json;
      try {
        json = XmlParser.parseString(this.xml, { compact: true });
      } catch (error) {
        consoleNotifyError(error);
        return;
      }
      if (!json) {
        return;
      }

      let namespace = get(json, 'tns:request._attributes.xmlns:tns');
      if (!namespace) {
        consoleNotifyError(this.$t('services.emulation.error.noTns'));
        return;
      } else if (!namespace.startsWith('request@')) {
        namespace = `request@${namespace}`;
      }
      const response = await serviceApi
        .searchService(`petitionType==${namespace}`, '', '', 'documents')
        .catch((error) => requestNotifyError(error));
      if (!response) {
        return;
      }

      const services = response.data as ServiceWithDocuments[];
      if (!services[0]) {
        consoleNotifyError(this.$t('services.emulation.error.noServiceByTns'));
        return;
      }
      this.serviceCard = services[0];
      this.$emit('get-service-card', this.serviceCard);
      return json;
    },
    readXmlToEditor(file) {
      const reader = new FileReader();
      reader.readAsText(file);
      reader.onload = () => {
        try {
          this.xml = xmlConverter.js2xml(xmlConverter.xml2js(reader.result), {
            spaces: 2,
          });
          this.isFileAdded = true;
        } catch (e) {
          consoleNotifyError(e);
          this.$refs.xmlUploaderRef.reset();
        }
      };
      reader.onerror = function () {
        consoleNotifyError(reader.error);
      };
    },
    onCmCodeChange(newCode) {
      if (!this.isFileUploaded) {
        this.xml = newCode;
      }
    },
    async onUploadClick() {
      const xmlByLines = this.xml.split('\n');
      const xml = new File(xmlByLines, this.xmlFilename, {
        type: 'text/plain',
      });
      this.loading = true;
      if (!this.serviceCard) {
        this.getServiceCard();
      }
      const response = await petitionApi.upload
        .apply(
          this,
          this.xsd
            ? [xml, this.beforeUploadStep, this.xsd]
            : [xml, this.beforeUploadStep]
        )
        .catch((error) => requestNotifyError(error))
        .finally(() => (this.loading = false));
      if (!response?.data) {
        return;
      }
      if (
        response.data.traceID?.toLowerCase() === 'unknownid' ||
        response.data.traceID?.toLowerCase() === 'empty'
      ) {
        consoleNotifyError(`traceId: ${response.data.traceID}`);
        return;
      }
      if (
        response.data?.endData?.errorCode ||
        response.data?.endData?.data.errorCode
      ) {
        this.$emit(
          'get-mz-trace-id',
          response.data.processTraceId || response.data.endData?.processTraceId
        );
        consoleNotifyError(
          response.data.endData?.errorCode ||
            response.data?.endData?.data?.errorCode
        );
        return;
      }
      const data = response.data;
      this.validationStatus = data.validationStatus;
      this.storeImport(data);
      if (data.stage === '2') {
        this.storeInteragencies(data.endData);
      } else if (this.beforeUploadStep === 3) {
        notifySuccess(
          this.$tc('services.emulation.success.interagenciesSuccessfullyCompleted')
        );
        this.storeChecks(data);
      }
      this.cmOptions.readOnly = 'no-cursor';
      this.cmOptions.disabled = true;
      this.isFileUploaded = true;
    },
    async getInteragencies() {
      this.interagenciesLoading = true;
      const response = await cwfApi
        .prepareMzProcess(this.traceId)
        .catch((error) => requestNotifyError(error))
        .finally(() => (this.interagenciesLoading = false));
      if (!response) {
        return;
      }
      if (
        response.data.endData?.errorCode ||
        response.data.data?.errorCode ||
        response.data.endData?.data.errorCode ||
        response.data.error
      ) {
        this.$emit('get-mz-trace-id', response.data.processTraceId);
        consoleNotifyError(
          response.data.endData?.errorCode ||
            response.data.data?.errorCode ||
            response.data.endData?.data.errorCode ||
            response.data.data
        );
        return;
      }
      if (!response.data.error) {
        this.storeInteragencies(response.data);
      }
    },
    onFilesUpload(file: UploadedDocument) {
      this.s3Documents.push(file);
    },
    storeImport(data: any) {
      this.traceId = data.traceID || data.processId?.ProcessImportId;
      this.$emit('get-import-trace-id', this.traceId);
      if (!data.endData?.error) {
        notifySuccess(
          this.$tc('services.emulation.success.importSuccessfullyCompleted')
        );
      } else {
        notifyError(this.$tc('services.emulation.error.importFailed'));
      }
    },
    storeInteragencies(data: any) {
      this.interagencies = data.data;
      this.mzTraceId = data.processTraceId;
      this.$emit('get-mz-trace-id', this.mzTraceId);
      this.step = 2;
      if (!data.endData?.error || !data.error) {
        notifySuccess(
          this.$tc('services.emulation.success.interagenciesSuccessfullyCompleted')
        );
      } else {
        notifyError(this.$tc('services.emulation.error.interagenciesFailed'));
      }
    },
    storeChecks(data: any) {
      if (!data.error) {
        this.$emit('get-checks', data);
        this.step = 3;
        notifySuccess(
          this.$tc('services.emulation.success.checksSuccessfullyReceived')
        );
      } else {
        this.$emit('get-checks-trace-id', data.processId?.DataPrepareId);
        notifyError(this.$tc('services.emulation.error.checksFailed'));
      }
    },
    onFilesRemoved(documentCode: string) {
      this.s3Documents = this.s3Documents.filter(
        (d) => d.documentCode !== documentCode
      );
    },
    async onGetChecksClick() {
      this.checksLoading = true;
      const response = await cwfApi
        .dataPrepareStart({
          data: {
            processTraceId: this.mzTraceId,
            interDepartmentReq: this.interagencies,
          },
        })
        .catch((error) => consoleNotifyError(error))
        .finally(() => (this.checksLoading = false));
      if (!response) {
        return;
      }
      if (!response.data.error) {
        this.storeChecks(response.data);
      }
    },
    onRemoved() {
      this.validationStatus = null;
      this.xsd = '';
      this.xml = '';
      this.isFileAdded = false;
      this.documents = [];
      this.isFileUploaded = false;
      this.cmOptions.readOnly = false;
      this.cmOptions.disabled = false;
      this.xmlFilename = '';
      this.onUploadDocumentsClicked = false;
      this.step = MIN_STEP;
      this.beforeUploadStep = MIN_STEP;
      this.serviceCard = null;
      this.interagencies = null;
      this.traceId = '';
      this.mzTraceId = '';
      this.$emit('remove');
    },
  },
});
</script>

<style></style>