<template>
  <div class="full-width">
    <q-card>
      <q-table
        v-if="rows"
        :title="$t('services.emulation.interdepartmentalRequests')"
        :columns="columns"
        :data="rows"
        row-key="name"
        hide-bottom
        :rows-per-page-options="[0]"
        :pagination.sync="pagination"
      >
        <template #body="props">
          <q-tr :props="props">
            <!-- первая колонка как есть -->
            <q-td :key="props.cols[0].name" :props="props" auto-width>
              {{
                props.row.response.mockRequest.headers.class
                  ? props.row.response.mockRequest.headers.class
                  : ''
              }}
            </q-td>

            <!-- вторая колонка с именем загруженного файла -->
            <q-td :key="props.cols[1].name" :props="props" auto-width>
              <div class="text-body1">{{ props.row.label1 }}</div>
              <div class="white-space-normal">{{ props.row.label2 }}</div>
            </q-td>

            <!-- третья колонка с тогглом загрузки файла -->
            <q-td :key="props.cols[2].name" :props="props" auto-width>
              <div class="row items-center justify-end">
                <q-btn
                  class="row justify-end flex-nowrap width-max-content"
                  @click="onExpandClick(props.row, props.rowIndex)"
                >
                  <svg
                    width="10"
                    height="11"
                    viewBox="0 0 10 11"
                    fill="none"
                    xmlns="http://www.w3.org/2000/svg"
                  >
                    <path
                      fill-rule="evenodd"
                      clip-rule="evenodd"
                      d="M5 0.5C5.27615 0.5 5.5 0.723858 5.5 1V6.22672L6.80027 4.82643C6.98817 4.62407 7.30454 4.61236 7.5069 4.80026C7.70925 4.98816 7.72097 5.30453 7.53307 5.50688L5.3664 7.84021C5.27179 7.9421 5.13904 7.99999 5 7.99999C4.86097 7.99999 4.72821 7.9421 4.63361 7.84021L2.46694 5.50688C2.27904 5.30453 2.29076 4.98816 2.49311 4.80026C2.69547 4.61236 3.01183 4.62407 3.19973 4.82643L4.5 6.22672V1C4.5 0.723858 4.72386 0.5 5 0.5ZM0.5 6.83332C0.776142 6.83332 1 7.05718 1 7.33332V8.00001C1 8.82846 1.67157 9.50001 2.5 9.50001H7.49998C8.32844 9.50001 8.99998 8.82847 8.99998 8.00001V7.33332C8.99998 7.05718 9.22384 6.83332 9.49998 6.83332C9.77612 6.83332 9.99998 7.05718 9.99998 7.33332V8.00001C9.99998 9.38075 8.88073 10.5 7.49998 10.5H2.5C1.1193 10.5 0 9.38076 0 8.00001V7.33332C0 7.05718 0.223858 6.83332 0.5 6.83332Z"
                      fill="#1491CF"
                    />
                  </svg>
                  <span class="text-primary">{{
                    props.row.expand
                      ? $t('services.emulation.cancel')
                      : $t('services.emulation.upload')
                  }}</span>
                  <svg
                    width="6"
                    height="3"
                    viewBox="0 0 6 3"
                    fill="none"
                    xmlns="http://www.w3.org/2000/svg"
                  >
                    <rect width="6" height="3" fill="#E5E5E5" />
                    <rect
                      width="1585"
                      height="800"
                      transform="translate(-1515 -379)"
                      fill="#FCFCFD"
                    />
                    <rect
                      width="1528"
                      height="800"
                      transform="translate(-1458 -379)"
                      fill="#2675A6"
                      fill-opacity="0.025"
                    />
                    <rect
                      x="-1064"
                      y="-237"
                      width="1118"
                      height="650"
                      rx="8"
                      fill="white"
                    />
                    <g clip-path="url(#clip0_3_6)">
                      <path
                        d="M-1044 -80C-1044 -82.2091 -1042.21 -84 -1040 -84H30C32.2091 -84 34 -82.2091 34 -80V152C34 154.209 32.2091 156 30 156H-1040C-1042.21 156 -1044 154.209 -1044 152V-80Z"
                        fill="#357EAC"
                        fill-opacity="0.05"
                      />
                      <path
                        d="M-1036 -8C-1036 -12.4183 -1032.42 -16 -1028 -16H18C22.4183 -16 26 -12.4183 26 -8V11C26 15.4183 22.4183 19 18 19H-1028C-1032.42 19 -1036 15.4183 -1036 11V-8Z"
                        fill="#FCFCFD"
                      />
                      <path
                        fill-rule="evenodd"
                        clip-rule="evenodd"
                        d="M0.646447 0.146447C0.841709 -0.0488155 1.15829 -0.0488155 1.35355 0.146447L3 1.79289L4.64645 0.146447C4.84171 -0.0488155 5.15829 -0.0488155 5.35355 0.146447C5.54882 0.341709 5.54882 0.658291 5.35355 0.853553L3.35355 2.85355C3.15829 3.04882 2.84171 3.04882 2.64645 2.85355L0.646447 0.853553C0.451184 0.658291 0.451184 0.341709 0.646447 0.146447Z"
                        fill="#1491CF"
                      />
                      <path
                        d="M-89 -9.5H7V-11.5H-89V-9.5ZM7 12.5H-89V14.5H7V12.5ZM-89 12.5C-95.0751 12.5 -100 7.57513 -100 1.5H-102C-102 8.6797 -96.1797 14.5 -89 14.5V12.5ZM18 1.5C18 7.57513 13.0751 12.5 7 12.5V14.5C14.1797 14.5 20 8.6797 20 1.5H18ZM7 -9.5C13.0751 -9.5 18 -4.57513 18 1.5H20C20 -5.6797 14.1797 -11.5 7 -11.5V-9.5ZM-89 -11.5C-96.1797 -11.5 -102 -5.6797 -102 1.5H-100C-100 -4.57513 -95.0751 -9.5 -89 -9.5V-11.5Z"
                        fill="#014874"
                        fill-opacity="0.18"
                      />
                      <path
                        d="M-1028 -15H18V-17H-1028V-15ZM25 -8V11H27V-8H25ZM18 18H-1028V20H18V18ZM-1035 11V-8H-1037V11H-1035ZM-1028 18C-1031.87 18 -1035 14.866 -1035 11H-1037C-1037 15.9706 -1032.97 20 -1028 20V18ZM25 11C25 14.866 21.866 18 18 18V20C22.9706 20 27 15.9706 27 11H25ZM18 -15C21.866 -15 25 -11.866 25 -8H27C27 -12.9706 22.9706 -17 18 -17V-15ZM-1028 -17C-1032.97 -17 -1037 -12.9706 -1037 -8H-1035C-1035 -11.866 -1031.87 -15 -1028 -15V-17Z"
                        fill="#014874"
                        fill-opacity="0.11"
                      />
                    </g>
                    <rect
                      x="-1063.5"
                      y="-236.5"
                      width="1117"
                      height="649"
                      rx="7.5"
                      stroke="#014874"
                      stroke-opacity="0.11"
                    />
                    <defs>
                      <clipPath id="clip0_3_6">
                        <rect
                          width="1078"
                          height="561"
                          fill="white"
                          transform="translate(-1044 -164)"
                        />
                      </clipPath>
                    </defs>
                  </svg>
                </q-btn>
              </div>
            </q-td>
          </q-tr>
          <q-tr
            v-show="props.row.expand"
            :props="props"
            :key="`${props.rowIndex}-file-uploader`"
          >
            <q-td colspan="100%">
              <div>
                <div v-if="props.row.response">
                  <div class="column no-wrap">
                    <span class="text-h6"
                      >{{ $t('services.emulation.request') }}:</span
                    >
                    <textarea class="code-textarea" disabled>{{
                      props.row.response.mockRequest.requestMsg
                        ? props.row.response.mockRequest.requestMsg
                        : 'запрос'
                    }}</textarea>
                  </div>

                  <div class="row items-center">
                    <span class="q-mr-sm"
                      >{{ $t('services.emulation.changeResponse') }}:</span
                    >
                    <q-select
                      v-model="props.row.code"
                      :options="props.row.codes"
                      map-options
                      option-label="code"
                      @input="(v) => onChangeCode(props.row, v, props.rowIndex)"
                    />
                  </div>

                  <div
                    v-if="props.row.code.code !== 'default'"
                    class="q-gutter-x-md row items-center"
                  >
                    <q-input
                      placeholder="Название"
                      v-model="props.row.responseTitle"
                    />
                    <add-file-button
                      :title="$t('services.emulation.selectFile')"
                      @added="(file) => onResponseAdded(file, props.row)"
                    />
                  </div>

                  <div class="column no-wrap q-pb-xl">
                    <span class="text-h6"
                      >{{ $t('services.emulation.response') }}:</span
                    >
                    <v-json-editor
                      :key="jsonEditorKey"
                      v-model="props.row.responseText"
                      height="400px"
                      :options="{
                        mode: 'code',
                        mainMenuBar: false,
                        onValidationError: setSchemaErrors,
                        onBlur: setLazySchemaErrors,
                      }"
                    />
                  </div>

                  <div>
                    <q-btn
                      v-if="props.row.code.code === CUSTOM_CODE"
                      color="primary"
                      filled
                      :label="$t('base.save')"
                      :disable="!props.row.responseTitle"
                      @click="
                        onSaveResponseClick(
                          props.row.responseTitle,
                          props.row.responseText,
                          props.row.response.mockRequest.headers.class,
                          props.row
                        )
                      "
                    />
                    <q-btn
                      v-else-if="props.row.code.code !== 'default'"
                      color="primary"
                      filled
                      :label="$t('base.update')"
                      :disable="!props.row.responseTitle"
                      @click="onUpdateResponseClick(props.row)"
                    />
                  </div>
                </div>
              </div>
            </q-td>
          </q-tr>
        </template>
      </q-table>
    </q-card>
  </div>
</template>

<script lang="ts">
// @ts-ignore
import VJsonEditor from 'v-jsoneditor';
import Vue from 'vue';
import { mapInteragenciesToRows } from '../utils';
import { consoleNotifyError, requestNotifyError } from '../utils';
import { cloneDeep } from 'lodash';
import AddFileButton from '../components/add-file-button.vue';
import { InteragenciesTableRow } from '../types.d';
import { ConstructorMzMockResponseApi } from '@openapi/constructor-database';
import { notifySuccess } from '@/utils/notify';

const constructorMzMockResponseApi = new ConstructorMzMockResponseApi();

export default Vue.extend({
  components: {
    AddFileButton,
    VJsonEditor,
  },
  props: {
    traceId: String,
    rowInteragencies: Object,
  },
  data() {
    return {
      rows: [] as any[],
      pagination: {
        page: 1,
        rowsPerPage: 0,
      },
      columns: [
        {
          name: 'name',
          label: 'Класс',
          field: 'name',
          align: 'left',
        },
        {
          name: 'file',
          label: 'Наименование / описание',
          field: 'file',
          align: 'left',
        },
        {
          name: 'action',
          label: 'Файл',
          field: 'action',
          align: 'right',
        },
      ],
      CUSTOM_CODE: 'custom',
      liveSchemaErrors: [],
      lazySchemaErrors: [],
      jsonEditorKey: 0,
    };
  },
  mounted() {
    this.setRows();
  },
  methods: {
    setRows() {
      if (this.rowInteragencies) {
        this.rows = mapInteragenciesToRows(this.rowInteragencies);
      } else {
        this.rows = [];
      }
    },
    async getCodesForRow(row: InteragenciesTableRow, rowIndex: number) {
      const clazz = row.response.mockRequest.headers.class;
      const response = await constructorMzMockResponseApi.searchConstructorMzMockResponse(
        `clazz==${clazz}`
      );
      if (!response) {
        return;
      }
      row.codes.push({
        code: 'default',
        responseMsg: row.response.mockResponse.responseMsg,
      });
      row.codes.push(...response.data);
      row.codes.push({
        code: this.CUSTOM_CODE,
        responseMsg: '',
      });
      this.$set(this.rows[rowIndex], 'code', row.codes[0]);

      let responseText = '';
      try {
        responseText = row.codes[0].responseMsg;
      } catch (e) {
        consoleNotifyError(e);
      }
      this.$set(this.rows[rowIndex], 'responseText', responseText);
    },
    async onExpandClick(row: any, rowIndex: number) {
      if (!row.codes?.length) {
        await this.getCodesForRow(row, rowIndex);
      }
      row.expand = !row.expand;
    },
    onChangeCode(row: any, codeObj: any, rowIndex: number) {
      let responseText = codeObj.responseMsg;
      if (codeObj.code !== this.CUSTOM_CODE) {
        try {
          responseText =
            typeof codeObj.responseMsg === 'string'
              ? JSON.parse(codeObj.responseMsg)
              : codeObj.responseMsg;
          this.$set(row, 'responseText', responseText);
          this.$set(row, 'responseTitle', row.code.code);
        } catch (e) {
          consoleNotifyError(e);
        }
      } else {
        this.$set(row, 'responseText', '');
        this.$set(row, 'responseTitle', '');
      }
      this.updateResponseMessage(row, responseText, codeObj.code);
      this.jsonEditorKey++;
    },
    async onUpdateResponseClick(row: any) {
      const id = row.code.id;
      const responseTitle = row.responseTitle;
      const responseMsg = JSON.stringify(row.responseText);
      const clazz = row.response.mockRequest.headers.class;

      try {
        const {
          data,
        } = await constructorMzMockResponseApi.updateConstructorMzMockResponse([
          {
            id,
            clazz,
            code: responseTitle,
            responseMsg,
          },
        ]);
        if (data.success) {
          notifySuccess(`Ответ ${responseTitle} успешно обновлён`);

          this.updateResponseMessage(row, row.responseText, responseTitle);
        }
      } catch (e) {
        requestNotifyError(e);
      }
    },
    async onSaveResponseClick(
      responseTitle: string,
      responseText: any,
      clazz: string,
      row: any
    ) {
      try {
        const responseMsg = JSON.stringify(responseText);
        const {
          data,
        } = await constructorMzMockResponseApi.createConstructorMzMockResponse([
          {
            clazz,
            code: responseTitle,
            responseMsg,
          },
        ]);
        if (data.success) {
          notifySuccess(`Ответ ${responseTitle} успешно сохранён`);

          const codeObj = {
            code: responseTitle,
            responseText,
            id: data.objectIds[0],
          };
          row.codes.push(codeObj);
          this.$set(row, 'code', codeObj);
          this.updateResponseMessage(row, responseText, responseTitle);
        }
      } catch (e) {
        requestNotifyError(e);
      }
    },
    updateResponseMessage(row: any, newResponseMsg: any, code: string) {
      const messageId = row.response.mockRequest.headers.id;
      const updatedInteragencies = cloneDeep(this.rowInteragencies);
      updatedInteragencies[messageId].mockResponse.responseMsg = cloneDeep(
        newResponseMsg
      );
      updatedInteragencies[messageId].mockResponse.code = code;
      this.$emit('interagencies-updated', updatedInteragencies);

      const updatedCodes = cloneDeep(row.codes);
      const ind = updatedCodes.findIndex((c: any) => c.code === row.code.code);
      updatedCodes[ind].responseMsg = cloneDeep(newResponseMsg);
      updatedCodes[ind].code = code;
      this.$set(row, 'codes', updatedCodes);
      this.$set(row, 'code', updatedCodes[ind]);

      this.$set(row, 'file', null);
    },
    setSchemaErrors(errors: any) {
      this.liveSchemaErrors = errors;
      if (this.lazySchemaErrors.length) {
        this.lazySchemaErrors = this.liveSchemaErrors;
      }
    },
    setLazySchemaErrors() {
      this.lazySchemaErrors = this.liveSchemaErrors;
    },
    async onResponseAdded(file: File, row: any) {
      const reader = new FileReader();
      reader.readAsText(file);
      reader.onload = () => {
        try {
          row.responseText = JSON.parse('' + reader.result);
        } catch (e) {
          consoleNotifyError(e);
        }
      };
      reader.onerror = function () {
        consoleNotifyError(reader.error);
      };
    },
  },
});
</script>

<style>
.white-space-normal {
  white-space: normal;
}

.flex-nowrap {
  flex-wrap: nowrap;
}

.width-max-content {
  width: max-content;
}

.w-auto {
  width: auto;
}

.interdepart-file-upload > .q-uploader__list {
  min-height: auto;
  padding: 0;
}

.interdepart-file-upload > .q-uploader__header {
  border-radius: inherit;
  background: transparent;
}

.interdepart-file-upload > .q-uploader__header::before {
  background: transparent;
}

.upload-btn {
  border: 1px solid rgba(1, 72, 116, 0.18);
  box-sizing: border-box;
  border-radius: 24px;
  color: #107abc;
  padding: 4px 12px;
  height: 32px;
  display: flex;
  flex-direction: row;
  align-items: center;
  text-transform: none;
}

.upload-btn__upload-icon {
  margin-right: 12px;
}

.code-wrapper {
  width: 75%;
}

.code-textarea {
  background-color: #eeeeee;
  word-break: normal;
  word-wrap: normal;
  overflow: auto;
  white-space: pre;
  width: 95%;
  height: 400px;
  opacity: 1 !important;
  color: black;
  cursor: default !important;
}
</style>