<i18n>
{
  "en": {
    "VerificationEdit": {
      "title": "verification edit",
      "createTitle": "verification create",
      "type": "Type",
      "code": "Code",
      "goal": "Goal code",
      "autolVerificationsTitle": "Autochecks",
      "manualVerificationsTitle": "Manual checks",
      "rejectCode": "Reject code",
      "name": "Name",
      "invertLabel": "Invert label",
      "basedOn": "Based on",
      "applicableForObjectType": "Applicable for",
      "noResult": "No directories",
      "applicability": "Applicability",
      "applicabilityApplication": "Conditions of applicability to an application",
      "applicabilityAttribute": "Attribute path in statement",
      "applicabilityEquality": "Comparison operator",
      "applicabilityValue": "What value to compare with",
      "subjectType": "Subject type",
      "attribute": "attribute",
      "isGoal": "Is the goal",
      "applicabilityType": "applicability type",
      "addApplicabilityTitle": "New applicability",
      "conditionType": "Condition type",
      "jsonEditorMode": "Json editor mode",
      "formMode": "Form mode",
      "withComment": "With comment"
    }
  },
  "ru": {
    "VerificationEdit": {
      "title": "Редактирование данных проверки",
      "createTitle": "Новая проверка",
      "type": "Тип",
      "code": "Код",
      "goal": "Код цели",
      "rejectCode": "Код отказа",
      "autolVerificationsTitle": "Aвтопроверки ",
      "manualVerificationsTitle": "Ручные проверки",
      "name": "Наименование",
      "invertLabel": "Инвертированое значение",
      "basedOn": "Основан на",
      "applicableForObjectType": "Применим к",
      "noResult": "Обьект не выбран",
      "applicability": "Условия проверки",
      "applicabilityApplication": "Условия применимости к заявлению",
      "applicabilityAttribute": "Путь к атрибуту в заявлении",
      "applicabilityEquality": "Оператор сравнения",
      "applicabilityValue": "С каким значением сравнивать",
      "subjectType": "Субъект",
      "attribute": "Атрибут субъекта",
      "applicabilityType": "Тип условия",
      "addApplicabilityTitle": "Новое условие",
      "conditionType": "Тип Выражения",
      "applicabilityError": "Выберите тип условия",
      "jsonEditorMode": "Режим редактора json",
      "formMode": "Режим формы",
      "isGoal": "Является целью",
      "saveSuccess": "Объект успешно изменен, для сохранения изменений надо сохранить услугу",
      "createSuccess": "Объект успешно создан, для сохранения изменений надо сохранить услугу",
      "withComment": "С комментарием"
    }
  }
}
</i18n>

<template>
  <div>
    <div
      class="flex items-center bg-white q-pa-md q-mt-md q-mx-md rounded-borders"
    >
      <q-btn
        padding="xs"
        class="text-grey-7 q-mr-md"
        color="grey-3"
        icon="arrow_back"
        @click="goBack"
      />

      <div class="title text-h6 text-grey-10">
        {{
          isEditForm
            ? $t('VerificationEdit.title')
            : $t('VerificationEdit.createTitle')
        }}
      </div>

      <div class="q-ml-auto">
        <q-toggle
          v-model="jsoneditorMode"
          class="q-mr-md"
          keep-color
          color="secondary"
          :options="toggleBtnOptions"
        />
        <q-btn
          v-if="isEditForm"
          label="Cохранить"
          unelevated
          color="primary"
          @click="edit"
        />
        <q-btn
          v-else
          label="Создать"
          unelevated
          color="primary"
          @click="create"
        />
      </div>
    </div>

    <div class="bg-white q-pa-md q-mt-md q-mx-md rounded-borders">
      <q-card-section class="q-pb-md q-gutter-y-md">
        <v-json-editor
          v-if="jsoneditorMode"
          ref="jsoneditor"
          v-model="dialogData"
          :options="{ mode: 'code' }"
          height="400px"
        />
        <div v-if="dialogData && !jsoneditorMode" class="q-gutter-y-md">
          <q-input
            v-model="dialogData.code"
            filled
            :label="$t('VerificationEdit.code')"
          />
          <!--            :readonly="isEditForm"-->

          <q-select
            v-if="dialogData.type"
            v-model="dialogData.type"
            filled
            emit-value
            map-options
            :options="verificationType"
            :label="$t('VerificationEdit.type')"
          />

          <q-checkbox
            v-if="dialogData.type === 'manual'"
            v-model="dialogData.withComment"
            :label="$t('VerificationEdit.withComment')"
          />

          <q-input
            v-model="dialogData.name"
            filled
            type="textarea"
            :label="$t('VerificationEdit.name')"
          />

          <q-input
            v-model="dialogData.invertLabel"
            filled
            type="textarea"
            :label="$t('VerificationEdit.invertLabel')"
          />

          <div v-if="dialogData" class="q-gutter-y-sm">
            <div>
              {{ $t('VerificationEdit.basedOn') }}
            </div>
            <div class="q-gutter-sm row">
              <div class="col">
                <q-select
                  v-model="dialogData.basedOn && dialogData.basedOn.type"
                  filled
                  :options="basedOnTypes"
                  :label="$t('VerificationEdit.type')"
                />
              </div>
              <div
                v-if="
                  !isEmpty(card) &&
                  dialogData.basedOn &&
                  dialogData.basedOn.type === 'mvz'
                "
                class="col"
              >
                <q-select
                  v-model="dialogData.basedOn && dialogData.basedOn.code"
                  filled
                  :options="interagencies"
                  :label="$t('VerificationEdit.name')"
                  map-options
                  @input="setBasedOn"
                />
              </div>
              <div
                v-else-if="
                  !isEmpty(card) &&
                  dialogData.basedOn &&
                  dialogData.basedOn.type === 'document'
                "
                class="col"
              >
                <q-select
                  v-model="dialogData.basedOn && dialogData.basedOn.code"
                  filled
                  :options="documents"
                  :label="$t('VerificationEdit.name')"
                  map-options
                  @input="setBasedOn"
                />
              </div>
              <div v-else class="col q-gutter-x-sm row">
                <div class="col">
                  <q-input
                    v-model="dialogData.basedOn && dialogData.basedOn.code"
                    filled
                    :label="$t('VerificationEdit.code')"
                  />
                </div>

                <div class="col">
                  <q-input
                    v-model="dialogData.basedOn && dialogData.basedOn.title"
                    filled
                    :label="$t('VerificationEdit.name')"
                  />
                </div>
              </div>
            </div>
          </div>

          <q-select
            v-model="dialogData.rejectCode"
            filled
            :options="rejectCodesList"
            :label="$t('VerificationEdit.rejectCode')"
            emit-value
            map-options
          />

          <q-input
            v-if="dialogData.applicableForObjectType"
            v-model="dialogData.applicableForObjectType"
            filled
            readonly
            :label="$t('VerificationEdit.applicableForObjectType')"
          />

          <div v-if="dialogData.applicability" class="q-gutter-sm">
            <div class="text-h6">
              {{ $t('VerificationEdit.applicability') }}
            </div>

            <div v-if="application">
              <div>
                {{ $t('VerificationEdit.applicabilityApplication') }}
              </div>
              <ConditionBlock
                v-if="application.condition"
                :goalsList="goalsList"
                :model="application.condition"
                :equality-type="equalityType"
                :type-options="typeOptions"
              >
                <template>
                  <q-btn
                    text-color="primary"
                    dense
                    icon="delete"
                    flat
                    @click="
                      deletecCondition(
                        application.condition,
                        'applicability.application.condition'
                      )
                    "
                  />
                </template>
              </ConditionBlock>
              <div v-if="application.and">
                (и)
                <div
                  v-for="(item, index) in application.and"
                  :key="`condition-${index}`"
                  class="q-gutter-y-sm"
                >
                  <ConditionBlock
                    v-if="item.condition"
                    :goalsList="goalsList"
                    :model="item.condition"
                    :equality-type="equalityType"
                    :type-options="typeOptions"
                  >
                    <template>
                      <q-btn
                        text-color="primary"
                        dense
                        icon="delete"
                        flat
                        @click="
                          deletecCondition(
                            item,
                            'applicability.application.and'
                          )
                        "
                      />
                    </template>
                  </ConditionBlock>
                </div>
              </div>
              <div v-if="application.or">
                (или)
                <div
                  v-for="(item, index) in application.or"
                  :key="`condition-${index}`"
                  class="q-gutter-y-sm"
                >
                  <ConditionBlock
                    v-if="item.condition"
                    :goalsList="goalsList"
                    :model="item.condition"
                    :equalityType="equalityType"
                    :typeOptions="typeOptions"
                  >
                    <template>
                      <q-btn
                        text-color="primary"
                        dense
                        icon="delete"
                        flat
                        @click="
                          deletecCondition(item, 'applicability.application.or')
                        "
                      />
                    </template>
                  </ConditionBlock>
                </div>
              </div>
            </div>

            <div v-if="subjects">
              <div
                v-for="(item, subjectIndex) in subjects"
                :key="`subject-${subjectIndex}`"
                class="q-gutter-y-md"
              >
                <div>Условия применимости к субъектам заявления</div>
                <q-select
                  v-model="item.subjectType"
                  :options="subjectTypesDictionary"
                  emit-value
                  map-options
                  filled
                  :label="$t('VerificationEdit.subjectType')"
                />
                <div v-if="item.conditions" class="q-gutter-y-md">
                  <ConditionBlock
                    v-if="item.conditions.condition"
                    :goalsList="goalsList"
                    :model="item.conditions.condition"
                    :equality-type="equalityType"
                    :type-options="typeOptions"
                  >
                    <template>
                      <q-btn
                        v-if="!isReadOnlyForm"
                        text-color="primary"
                        dense
                        icon="delete"
                        flat
                        @click="
                          deletecCondition(
                            item.conditions.condition,
                            `applicability.subjects[${subjectIndex}].conditions.condition`
                          )
                        "
                      />
                    </template>
                  </ConditionBlock>
                  <div v-if="item.conditions.and">
                    (и)
                    <div
                      v-for="(condition, index) in item.conditions.and"
                      :key="`condition-${index}`"
                      class="q-gutter-sm"
                    >
                      <ConditionBlock
                        v-if="condition.condition"
                        :goalsList="goalsList"
                        :model="condition.condition"
                        :equality-type="equalityType"
                        :type-options="typeOptions"
                      >
                        <template>
                          <q-btn
                            text-color="primary"
                            dense
                            icon="delete"
                            flat
                            @click="
                              deletecCondition(
                                condition.condition,
                                `applicability.subjects[${subjectIndex}].conditions.and`
                              )
                            "
                          />
                        </template>
                      </ConditionBlock>
                    </div>
                  </div>
                  <div v-if="item.conditions.or">
                    (или)
                    <div
                      v-for="(condition, index) in item.conditions.or"
                      :key="`condition-${index}`"
                    >
                      <ConditionBlock
                        v-if="condition.condition"
                        :goalsList="goalsList"
                        :model="condition.condition"
                        :equality-type="equalityType"
                        :type-options="typeOptions"
                      >
                        <template>
                          <q-btn
                            text-color="primary"
                            dense
                            icon="delete"
                            flat
                            @click="
                              deletecCondition(
                                condition.condition,
                                `applicability.subjects[${subjectIndex}].conditions.or`
                              )
                            "
                          />
                        </template>
                      </ConditionBlock>
                    </div>
                  </div>
                </div>
              </div>
            </div>
            <div>
              <q-btn
                v-if="!addApplicability"
                color="white"
                text-color="primary"
                outline
                @click="addApplicability = true"
              >
                Добавить условие
              </q-btn>
            </div>

            <div
              v-if="addApplicability && newApplicabilityModel"
              class="q-gutter-sm"
            >
              {{ $t('VerificationEdit.addApplicabilityTitle') }}
              <div class="q-gutter-sm">
                <q-select
                  v-model="newApplicabilityModel.applicabilityType"
                  filled
                  :label="$t('VerificationEdit.applicabilityType')"
                  :options="applicabilityType"
                />

                <q-select
                  v-model="newApplicabilityModel.conditionType"
                  filled
                  :label="$t('VerificationEdit.conditionType')"
                  :options="conditionType"
                  emit-value
                  map-options
                />

                <q-select
                  v-if="
                    newApplicabilityModel.applicabilityType &&
                    newApplicabilityModel.applicabilityType === 'subjects'
                  "
                  v-model="newApplicabilityModel.subjectType"
                  :options="subjectTypesDictionary"
                  emit-value
                  map-options
                  filled
                  :label="$t('VerificationEdit.subjectType')"
                />
              </div>
              <q-checkbox
                v-model="newApplicabilityModel.isGoalAttribute"
                :label="$t('VerificationEdit.isGoal')"
                @input="newApplicabilityModel.value = void 0"
              />
              <q-select
                filled
                v-if="newApplicabilityModel.isGoalAttribute"
                v-model="newApplicabilityModel.value"
                :options="goalsList"
                :label="$t('VerificationEdit.goal')"
                multiple
                use-chips
              />
              <div class="row q-gutter-sm" v-else>
                <div class="col">
                  <q-input
                    v-model="newApplicabilityModel.attribute"
                    filled
                    :label="$t('VerificationEdit.attribute')"
                  />
                </div>

                <div class="col">
                  <q-select
                    v-model="newApplicabilityModel.equality"
                    filled
                    :label="$t('VerificationEdit.applicabilityEquality')"
                    :options="equalityType"
                  />
                </div>
                <div class="col">
                  <q-input
                    v-if="
                      newApplicabilityModel.typeValue &&
                      newApplicabilityModel.typeValue === 'number'
                    "
                    v-model.number="newApplicabilityModel.value"
                    filled
                    type="number"
                    :label="$t('VerificationEdit.applicabilityValue')"
                  />
                  <q-checkbox
                    v-else-if="
                      newApplicabilityModel.typeValue &&
                      newApplicabilityModel.typeValue === 'boolean'
                    "
                    v-model="newApplicabilityModel.value"
                    :label="$t('VerificationEdit.applicabilityValue')"
                  />
                  <q-input
                    v-else
                    v-model="newApplicabilityModel.value"
                    filled
                    :label="$t('VerificationEdit.applicabilityValue')"
                  />
                </div>
                <div class="col">
                  <q-select
                    v-model="newApplicabilityModel.typeValue"
                    filled
                    :label="$t('VerificationEdit.type')"
                    :options="typeOptions"
                    emit-value
                    map-options
                    @input="newApplicabilityModel.value = void 0"
                  />
                </div>
              </div>
              <q-btn unelevated color="primary" @click="addNewApplicability">
                Добавить
              </q-btn>
            </div>
          </div>
        </div>
      </q-card-section>
    </div>
  </div>
</template>
<script lang="ts">
// @ts-nocheck
// @ts-ignore
import VJsonEditor from 'v-jsoneditor';
import get from 'lodash/get';
import set from 'lodash/set';
import isEmpty from 'lodash/isEmpty';
import isEqual from 'lodash/isEqual';
import cloneDeep from 'lodash/cloneDeep';
import ConditionBlock from '@components/cards/verifications/ConditionBlock.vue';
import { notifyError, notifySuccess } from '@utils/notify';

const STATEMENT_GOAL_NAME = 'statement.goal';

const GOAL_EQUALITY = 'in';

export default {
  name: 'Verification',
  components: {
    VJsonEditor,
    ConditionBlock,
  },
  props: ['common', 'model', 'user-task'],

  data() {
    return {
      jsoneditorMode: false,

      toggleBtnOptions: [
        {
          label: this.$t('VerificationEdit.jsonEditorMode'),
          value: true,
        },
        {
          label: this.$t('VerificationEdit.formMode'),
          value: false,
        },
      ],

      dialogData: null,

      card: null,

      mode: 'edit',

      addApplicability: false,

      modelDump: null,

      unsavedChanges: false,

      dialogOpen: false,

      defaultModel: {
        code: '',
        type: 'manual',
        name: '',
        invertLabel: '',
        applicability: {
          application: null,
          subjects: [],
        },
        basedOn: {
          type: '',
          code: '',
          title: '',
        },
        rejectCode: '',
      },

      defaultApplicabilityModel: {
        applicabilityType: '',
        conditionType: 'condition',
        subjectType: '',
        attribute: '',
        equality: '',
        value: void 0,
        typeValue: '',
        isGoalAttribute: false,
      },

      newApplicabilityModel: null,

      verificationType: [
        {
          label: 'Ручная проверка',
          value: 'manual',
        },
        {
          label: 'Автопроверка',
          value: 'auto',
        },
      ],
      conditionType: [
        {
          label: 'Базовое условие',
          value: 'condition',
        },
        {
          label: 'И',
          value: 'and',
        },
        {
          label: 'Или',
          value: 'or',
        },
        {
          label: 'Исключающая или',
          value: 'xor',
        },
      ],
      applicabilityType: ['application', 'subjects'],
      equalityType: [
        '==',
        '!=',
        '<',
        '>',
        '>=',
        '<=',
        'in',
        'not in',
        'like',
        'not like',
        'is null',
        'not null',
      ],
      typeOptions: [
        {
          label: 'Строка',
          value: 'string',
        },
        {
          label: 'Номер',
          value: 'number',
        },
        {
          label: 'Булево',
          value: 'boolean',
        },
      ],

      basedOnTypes: ['document', 'mvz', 'application'],
    };
  },

  computed: {
    application() {
      return get(this.dialogData, 'applicability.application');
    },

    subjects() {
      return get(this.dialogData, 'applicability.subjects');
    },

    isEditForm() {
      return this.mode === 'edit';
    },
    code() {
      return get(this.common, 'id', 'create');
    },
    verifications() {
      return get(this.card, 'verifications', []);
    },
    serviceId() {
      return get(this.$route, 'query.service', '');
    },
    rejectCodesList() {
      return get(this.card, 'rejects', []).map((reject) => {
        return {
          label: reject.name,
          value: reject.code,
        };
      });
    },
    interagencies() {
      return get(this.card, 'interagencies', []).map((interagence) => {
        return {
          label: interagence.description,
          value: interagence.class,
        };
      });
    },

    goalsList() {
      return get(this.card, 'goalsList', []).map((i) => +i.value);
    },

    documents() {
      return get(this.card, 'documents', []).map((document) => {
        return {
          label: document.name,
          value: document.code,
        };
      });
    },

    subjectTypesDictionary() {
      const card = this.$store.getters['registryService/services/servicesCard'];
      return card.subjectsList || [];
    },
  },
  watch: {
    dialogData: {
      handler(data) {
        this.unsavedChanges = data !== null && !isEqual(data, this.modelDump);
        this.$root.$emit('unsavedChanges', this.unsavedChanges);
      },
    },
  },
  mounted() {
    this.newApplicabilityModel = cloneDeep(this.defaultApplicabilityModel);
    this.init();
    this.modelDump = this.dialogData;
  },

  destroyed() {
    this.clearModel();
  },

  methods: {
    isEmpty,
    addType(condition) {
      const value = condition?.value;
      const type = condition?.typeValue?.value;

      // todo test condition
      // eslint-disable-next-line eqeqeq
      return !(type === 'boolean' && !value == 'true' && !value == 'false');
    },
    addNewApplicability() {
      if (
        !this.newApplicabilityModel ||
        !this.newApplicabilityModel.applicabilityType
      ) {
        notifyError(this.$t('VerificationEdit.applicabilityError'));
        return;
      }

      const applicability =
        (this.dialogData && this.dialogData.applicability) || {};

      const {
        applicabilityType,
        subjectType,
        conditionType,
        isGoalAttribute,
      } = this.newApplicabilityModel;

      const isBaseConditionType = conditionType === 'condition';

      const condition = {
        condition: {
          attribute: isGoalAttribute
            ? STATEMENT_GOAL_NAME
            : get(this.newApplicabilityModel, 'attribute'),
          equality: isGoalAttribute
            ? GOAL_EQUALITY
            : get(this.newApplicabilityModel, 'equality'),
          value: get(this.newApplicabilityModel, 'value'),
        },
      };

      if (applicabilityType === 'application') {
        if (isBaseConditionType) {
          if (!applicability.application) {
            applicability.application = {};
          }

          applicability.application[conditionType] = condition.condition;
        } else {
          if (!applicability.application[conditionType]) {
            applicability.application[conditionType] = [];
          }

          applicability.application[conditionType].push(condition);
        }
      }

      if (applicabilityType === 'subjects') {
        if (!applicability.subjects) {
          applicability.subjects = [];
        }

        const isSubjectsType = applicability.subjects.some(
          (i) => i.subjectType.toString() === subjectType
        );

        if (isSubjectsType) {
          applicability.subjects.forEach((subject) => {
            if (
              subject.subjectType.toString() === subjectType &&
              subject.conditions
            ) {
              if (isBaseConditionType) {
                subject.conditions[conditionType] = condition.condition;
              } else {
                if (!subject.conditions[conditionType]) {
                  subject.conditions[conditionType] = [];
                }

                subject.conditions[conditionType].push(condition);
              }
            }
          });
        } else {
          const newSubject = {
            subjectType: subjectType,
            conditions: {},
          };

          if (isBaseConditionType) {
            newSubject.conditions[conditionType] = condition.condition;
          } else {
            newSubject.conditions[conditionType] = [];
            newSubject.conditions[conditionType].push(condition);
          }

          applicability.subjects.push(newSubject);
        }
      }

      this.dialogData.applicability = applicability;
      this.newApplicabilityModel = cloneDeep(this.defaultApplicabilityModel);
      this.addApplicability = false;
      this.$nextTick(() => this.$forceUpdate());
    },

    edit() {
      const result = this.card.verifications.map((it) =>
        it.code === this.code ? this.dialogData : it
      );
      this.card.verifications = result;
      this.$store.commit('registryService/services/unsavedChanges', true);
      this.$store.dispatch(
        'registryService/services/setCardForJson',
        this.card
      );
      this.unsavedChanges = false;
      this.$root.$emit('unsavedChanges', this.unsavedChanges);
      notifySuccess(this.$t('VerificationEdit.saveSuccess'));
    },

    create() {
      if (!this.dialogData) return;
      const verifications = this.card.verifications || [];
      verifications.push(this.dialogData);
      this.card.verifications = verifications;
      this.$store.commit('registryService/services/unsavedChanges', true);
      this.$store.dispatch(
        'registryService/services/setCardForJson',
        this.card
      );
      this.unsavedChanges = false;
      this.$root.$emit('unsavedChanges', this.unsavedChanges);
      notifySuccess(this.$t('VerificationEdit.createSuccess'));
    },
    deletecCondition(val, path) {
      let condition = get(this.dialogData, path);
      if (Array.isArray(condition)) {
        condition = condition.filter((i) => i !== val);
        set(this.dialogData, path, condition);
        return;
      }
      if (isEqual(condition, val)) {
        set(this.dialogData, path, void 0);
      }
    },
    clearModel() {
      this.jsoneditorMode = false;
      this.unsavedChanges = false;
      this.$root.$emit('unsavedChanges', this.unsavedChanges);
    },
    goBack() {
      if (
        !this.unsavedChanges ||
        (this.unsavedChanges &&
          window.confirm(
            'На странице есть несохраненные изменения. Продолжить?'
          ))
      ) {
        this.$router.push({
          name: 'cards',
          params: {
            id: this.serviceId,
            path: 'services',
            noCommit: true,
          },
          query: {
            active: 'verifications',
            components: this.$store.getters[
              'cardComponents/services/components'
            ],
          },
        });
      }
    },

    setBasedOn(val) {
      set(this.dialogData, 'basedOn.code', val.value);
      set(this.dialogData, 'basedOn.title', val.label);
    },

    async init() {
      let service = this.$store.getters[
        'registryService/services/servicesCard'
      ];

      if (isEmpty(service)) {
        service = await this.$store.dispatch(
          'registryService/services/getServiceMeta',
          {
            id: this.serviceId,
          }
        );
      }

      this.card = cloneDeep(service);

      if (this.code === 'create') {
        this.mode = 'create';
        const dialogData = cloneDeep(this.defaultModel);
        if (this.dialogData && !this.dialogData.basedOn) {
          dialogData.basedOn = { code: null, title: null, type: null };
        }
        this.dialogData = dialogData;
        return;
      }

      const dialogData = cloneDeep(
        this.verifications.find((i) => i.code === this.code)
      );
      if (this.dialogData && !this.dialogData.basedOn) {
        dialogData.basedOn = { code: null, title: null, type: null };
      }
      this.dialogData = dialogData;
    },
  },
};
</script>
