<template>
  <operation-dialog
    persistent
    sign
    ref="dialog"
    :title="organizationName"
    sub="Редактирование организации"
    v-model="opened"
    @hide="$emit('close')"
  >
    <div class="EditModalForm">
      <r-input
        class="EditModalForm__Field"
        label="Полное наименование*"
        v-model="editOrganization.fullname"
        validate-on-blur
        :rules="[(val) => !isEmptyVal(val) || 'Обязательное поле']"
      />
      <r-input
        class="EditModalForm__Field"
        label="ОПФ"
        v-model="editOrganization.leg"
      />
      <r-input
        class="EditModalForm__Field"
        label="Сокращённое наименование*"
        v-model="editOrganization.shortname"
        validate-on-blur
        :rules="[(val) => !isEmptyVal(val) || 'Обязательное поле']"
      />
      <r-input
        class="EditModalForm__Field"
        label="Код военного комиссариата"
        v-model="editOrganization.militaryCode"
        :rules="[
          (val) =>
            !val || val.match(/^[0-9]{8}$/) || 'Должен состоять из 8 цифр',
        ]"
      />
      <div class="EditModalForm__Field">
        <span class="EditModalForm__FieldLabel">Адрес организации</span>
        <BasicMAddressComponent
          :id.sync="editOrganization.addressId"
          :value.sync="editOrganization.address"
          filled
          dense
          options-dense
          dropdown-icon="pgs-shevron-down-off"
          :showManualEnter="false"
        />
      </div>
      <div class="EditModalForm__Field">
        <span class="EditModalForm__FieldLabel">
          Почтовый адрес организации
        </span>
        <BasicMAddressComponent
          :id.sync="editOrganization.postalAddressId"
          :value.sync="editOrganization.postalAddress"
          filled
          dense
          options-dense
          dropdown-icon="pgs-shevron-down-off"
          :showManualEnter="false"
        />
      </div>
      <r-select
        label="Субъект РФ*"
        :options="regionOptions"
        v-model="editOrganization.region"
        emit-value
        map-options
        clearable
        :rules="[(val) => !!val || 'Обязательное поле']"
      />
      <r-input
        class="EditModalForm__Field"
        label="Часовой пояс"
        v-model="editOrganization.timezone"
        :rules="[
          (val) => !val || rulesTimezone(val) || 'Должен быть в формате +01:30',
        ]"
      />
      <!-- TODO: создать компонент q-select с инпутом -->
      <div class="EditModalForm__Field">
        <span class="EditModalForm__FieldLabel">Вышестоящая организация</span>
        <q-select
          v-model="parentOrganizationSelected"
          dense
          options-dense
          filled
          menu-anchor="bottom start"
          :options="optionsOrg"
          :loading="loadingOrg"
          dropdown-icon="pgs-shevron-down-off"
          option-label="shortname"
          option-value="id"
          use-input
          input-debounce="1000"
          @filter="filterOrg"
        />
      </div>
      <r-select
        class="EditModalForm__Field"
        label="Тип организации"
        :options="orgTypes"
        v-model="editOrganization.govOrganizationType"
        emit-value
        map-options
      />
      <div class="EditModalForm__Field">
        <span class="EditModalForm__FieldLabel">
          Дата гос. регистрации организации
        </span>
        <q-input dense filled v-model="govRegistrationDate" :mask="inputMask">
          <template v-slot:append>
            <q-icon name="event" class="EditModalForm__FieldIcon">
              <q-popup-proxy
                ref="qDateProxy"
                transition-show="scale"
                transition-hide="scale"
              >
                <q-date v-model="govRegistrationDate" :mask="dateMask" />
              </q-popup-proxy>
            </q-icon>
          </template>
        </q-input>
      </div>
      <r-input
        class="EditModalForm__Field"
        label="ИНН*"
        v-model="editOrganization.inn"
        validate-on-blur
        :rules="[
          (val) => val.match(/^[0-9]{10}$/) || 'Должен состоять из 10 цифр',
        ]"
      />
      <r-input
        class="EditModalForm__Field"
        label="ОГРН*"
        v-model="editOrganization.ogrn"
        validate-on-blur
        :rules="[
          (val) => val.match(/^[0-9]{13}$/) || 'Должен состоять из 13 цифр',
        ]"
      />
      <r-input
        class="EditModalForm__Field"
        label="КПП"
        v-model="editOrganization.kpp"
        :rules="[
          (val) =>
            !val.length ||
            val.match(/^[0-9]{9}$/) ||
            'Должен состоять из 9 цифр',
        ]"
      />
      <r-input
        class="EditModalForm__Field"
        label="ОКТМО"
        v-model="editOrganization.oktmo"
      />
      <r-input
        class="EditModalForm__Field"
        label="Адрес электронной почты"
        v-model="editOrganization.email"
        type="email"
      >
        <template v-slot:icon>
          <q-icon name="email" />
        </template>
      </r-input>
      <div class="EditModalForm__Field">
        <span class="EditModalForm__FieldLabel">Телефон</span>
        <q-input
          fill-mask
          filled
          dense
          mask="+7 (###) ###-##-##"
          unmasked-value
          v-model="editOrganization.phone"
        >
          <template v-slot:prepend>
            <q-icon name="phone" />
          </template>
        </q-input>
      </div>
      <div class="EditModalForm__TogglesBlock">
        <q-toggle
          v-model="editOrganization.reportsEnabled"
          :label="
            editOrganization.reportsEnabled
              ? 'Включать в отчеты'
              : 'Исключать из отчетов'
          "
        />
        <q-toggle
          v-model="editOrganization.enabled"
          :label="editOrganization.enabled ? 'Заблокировать' : 'Разблокировать'"
          :true-value="false"
          :false-value="true"
        />
      </div>
    </div>
    <template #process>
      <result-block
        header="Обновление информации об организации"
        icon="pgs-document"
        type="info"
      />
    </template>
    <template #result>
      <result-block :header="resultMessage" :type="resultType" />
    </template>
    <template #left-actions-panel>
      <r-btn
        outline
        label="Закрыть"
        icon="pgs-close"
        color="primary"
        @click="$emit('close')"
      />
    </template>
    <template #right-actions-panel>
      <r-btn
        v-if="operationDialog && operationDialog.formState === 'start'"
        outline
        label="Сохранить"
        icon="pgs-save"
        positive
        :disable="!validateForm"
        @click="submit"
      />
    </template>
  </operation-dialog>
</template>

<script lang="ts">
import { Component, Prop, Mixins, Watch, Ref } from 'vue-property-decorator';
import { OrganizationWithParent } from '@/models/OrganizationWithParent';
import RInput from '@/recruits/components/common/r-input/index.vue';
import RSelect from '@/recruits/components/common/r-select.vue';
import BasicMAddressComponent from '@components/m-address/index.vue';
import isPlainObject from 'lodash/isPlainObject';
import {
  OrganizationApi,
  GraphApi,
  RegionApi,
  Organization,
} from '@openapi/idm';
import get from 'lodash/get';
import ProcessStarter from '@/mixins/ProcessStarter';
import { DateFormat } from '@constants/utils/format-date';
import { convertDateFormat } from '@utils/format-date';
import OperationDialog from '@/components/common/operation-dialog/index.vue';
import isString from 'lodash/isString';

const regionApi = new RegionApi();
const organizationApi = new OrganizationApi();
const graphApi = new GraphApi();

const ORGANIZATION = 'Organization';

@Component({
  components: {
    RInput,
    RSelect,
    BasicMAddressComponent,
  },
})
export default class EditOrganizationModal extends Mixins(ProcessStarter) {
  @Prop({ default: null }) organization: OrganizationWithParent | null;
  @Prop({ default: 'EditOrganizationIDMProcess' })
  declare processKey: string;

  @Ref('dialog') operationDialog: OperationDialog;

  loading = false;
  opened = false;

  editOrganization: OrganizationWithParent = {
    id: '',
    name: '',
    shortname: '',
    fullname: '',
    dns: '',
    ogrn: '',
    inn: '',
  };

  get organizationName(): string {
    return (
      this.organization?.fullname ||
      this.organization?.shortname ||
      this.organization?.name ||
      ''
    );
  }

  orgTypes: Array<{ label: string; value: string }> = [];
  regionOptions: Array<{ label: string; value: string }> = [];

  optionsOrg: Organization[] = [];
  loadingOrg = false;
  parentOrganizationSelected: Organization | null = null;
  govRegistrationDate = '';

  resultType: 'positive' | 'negative' | '' = '';
  resultMessage = '';

  @Watch('organization')
  private async organizationHandler(): Promise<void> {
    // openedAccountHandler приходит null - значит надо закрыть окно
    this.opened = false;
    this.resultType = '';
    this.orgTypes = [];
    this.regionOptions = [];

    this.optionsOrg = [];
    this.loadingOrg = false;
    this.parentOrganizationSelected = null;
    this.govRegistrationDate = '';
    this.operationDialog.reset();
    if (!this.organization?.id) return;
    this.editOrganization = JSON.parse(JSON.stringify(this.organization));
    this.opened = true;

    // get default options
    await this.getRegions();
    await this.getOrgTypes();
    await this.getOrganizations();

    if (
      this.editOrganization.parent &&
      this.editOrganization.parent.schema === ORGANIZATION
    ) {
      this.parentOrganizationSelected = JSON.parse(
        JSON.stringify(this.editOrganization.parent)
      );
    }

    if (!this.editOrganization.region) {
      graphApi
        .flatten('Organization', 'outgoing', [this.editOrganization.id], 1000, [
          'Region,Organization',
        ])
        .then(({ data }) => {
          if (Array.isArray(data) && data.length > 0) {
            const regionObject = data.find(
              (item) => get(item, 'schema') === 'Region'
            );

            this.editOrganization.region = get(regionObject, 'id', '');
          }
        })
        .catch(() => {
          throw new Error(
            '[components][forms][OrganizationsFormBasic][graphApi]'
          );
        });
    }

    if (this.editOrganization.govRegistrationDate) {
      this.govRegistrationDate = convertDateFormat(
        this.editOrganization.govRegistrationDate,
        DateFormat.dashedDate,
        this.dateMask
      );
    }
  }

  async getOrgTypes(): Promise<void> {
    await this.$store
      .dispatch('registryService/referenceBooks/fetchReferenceBook', {
        id: 'rosregister_declarant_kind',
        limit: 200,
      })
      .then((dict) => {
        if (isPlainObject(dict)) {
          // eslint-disable-next-line array-callback-return
          Object.entries(dict).map(([key, value]) => {
            this.orgTypes.push({
              value: key,
              label: get(value, 'value', ''),
            });
          });
        }
      });
  }

  async getRegions(): Promise<void> {
    await regionApi
      .searchRegions()
      .then(({ data }) => {
        if (Array.isArray(data) && data.length > 0) {
          this.regionOptions = data.map((regionObject) => {
            return {
              value: get(regionObject, 'id'),
              label: get(regionObject, 'fullname') || get(regionObject, 'name'),
            };
          });
        }
      })
      .catch(() => {
        throw new Error(
          '[components][forms][OrganizationsFormsBasic][searchRegions]'
        );
      });
  }

  async getOrganizations(findOrgString?: string): Promise<void> {
    if (!this.loadingOrg) {
      this.loadingOrg = true;
      const query = findOrgString
        ? `fullname=like='%${findOrgString}%' or name=like='%${findOrgString}%'`
        : '';
      await organizationApi
        .searchOrganizations(undefined, query)
        .then((response) => {
          this.optionsOrg = response.data || [];
        })
        .finally(() => {
          this.loadingOrg = false;
        });
    }
  }

  /**
   * Функция фильтрации в поле выбора ролей
   * @param {string} val
   * @param {function} update
   */
  async filterOrg(val: string, update: () => void): Promise<void> {
    if (val.length > 1 || val === '') {
      await this.getOrganizations(val);
      update();
    }
  }

  get regionLabel(): string {
    let label = '';

    if (
      this.editOrganization.region &&
      Array.isArray(this.regionOptions) &&
      this.regionOptions.length > 0
    ) {
      const regionObject = this.regionOptions.find(
        (item) => item.value === this.editOrganization.region
      );

      label = get(regionObject, 'label', '');
    }

    return label || 'Не выбрано';
  }

  rulesTimezone(timezone: string): string | boolean {
    const regex = /^[+|-]((0[0-9]|1[0-1]):([0-5][0-9])|12:00)$/;
    const regexMinusZero = /^-00:00$/;
    return regex.test(timezone) && !regexMinusZero.test(timezone);
  }

  get dateMask(): string {
    return this.$store.getters['i18N/localeMask'].date;
  }

  get inputMask(): string {
    return this.$store.getters['i18N/localeMask'].input;
  }

  isEmptyVal(val: string | null): boolean {
    return isString(val) ? !val.trim().length : true;
  }

  removeSpaces(val: string): string {
    return val.trim().replace(/ {1,}/g, ' ');
  }

  get validateForm(): boolean {
    return (
      !this.isEmptyVal(this.editOrganization.fullname) &&
      !this.isEmptyVal(this.editOrganization.shortname) &&
      (!this.editOrganization.militaryCode?.length ||
        !!this.editOrganization.militaryCode.match(/^[0-9]{8}$/)) &&
      !!this.editOrganization.region &&
      (!this.editOrganization.timezone?.length ||
        !!this.rulesTimezone(this.editOrganization.timezone)) &&
      !!this.editOrganization.inn.match(/^[0-9]{10}$/) &&
      !!this.editOrganization.ogrn.match(/^[0-9]{13}$/) &&
      (!this.editOrganization.kpp?.length ||
        !!this.editOrganization.kpp.match(/^[0-9]{9}$/))
    );
  }

  async submit(): Promise<void> {
    if (!this.validateForm) {
      return;
    }
    this.operationDialog.toProcess();
    const dataObject: {
      organization: Organization & { parent: string };
      transSertDelete: boolean;
      transExit: boolean;
      parentLabel: string;
      regionLabel: string;
    } = {
      organization: {
        certificate: this.editOrganization.certificate,
        aliasKey: this.editOrganization.aliasKey,
        passKey: this.editOrganization.passKey,
        enabled: this.editOrganization.enabled,
        id: this.editOrganization.id,
        email: this.editOrganization.email,
        fullname: this.removeSpaces(this.editOrganization.fullname),
        inn: this.editOrganization.inn,
        kpp: this.editOrganization.kpp,
        ogrn: this.editOrganization.ogrn,
        oktmo: this.editOrganization.oktmo,
        govOrganizationType: this.editOrganization.govOrganizationType,
        phone: this.editOrganization.phone,
        reportsEnabled: this.editOrganization.reportsEnabled,
        shortname: this.removeSpaces(this.editOrganization.shortname),
        militaryCode: this.editOrganization.militaryCode || 'emptyValue',
        timezone: this.editOrganization.timezone,
        addressId: this.editOrganization.addressId,
        address: this.editOrganization.address,
        postalAddressId: this.editOrganization.postalAddressId,
        postalAddress: this.editOrganization.postalAddress,
        dns: this.editOrganization.dns,
        name: this.editOrganization.dns,
        leg: this.editOrganization.leg,
        parent:
          this.parentOrganizationSelected?.id ||
          this.editOrganization.region ||
          '',
        region: this.editOrganization.region || '',
      },
      transSertDelete: false,
      transExit: false,
      parentLabel: this.parentOrganizationSelected?.shortname || 'Не выбрано',
      regionLabel: this.regionLabel,
    };

    if (this.govRegistrationDate) {
      dataObject.organization.govRegistrationDate = convertDateFormat(
        this.govRegistrationDate,
        this.dateMask,
        DateFormat.dashedDate
      );
    }

    try {
      const traceId = await this.startProcess({
        organization: dataObject.organization,
      });

      this.registerListener((message, removeListener) => {
        if (traceId !== message.traceId) return;
        if (message?.body?.type === 'finish') {
          this.resultType = 'positive';
          this.resultMessage = 'Информация об организации обновлена';
          removeListener();
          this.$emit('refresh');
        }

        if (message?.body?.type === 'error') {
          this.resultType = 'negative';
          // get т.к. message может быть Task | PushMessage, а в Task нет поля msg
          this.resultMessage = get(
            message,
            'body.msg.message',
            'Произошла непредвиденная ошибка'
          );
          removeListener();
        }
      });
    } catch (error: any) {
      this.resultType = 'negative';
      this.$q.notify({
        message: error.message,
        color: 'negative',
      });
    } finally {
      this.operationDialog.toResult();
    }
  }
}
</script>

<style lang="scss" scoped>
.EditModalForm {
  &__FieldLabel {
    font-family: 'Golos Text', sans-serif;
    font-style: normal;
    display: inline-block;
    cursor: pointer;
    font-size: 12px;
    line-height: 16px;
    margin-bottom: 4px;
    font-weight: 600;
    color: rgba(2, 12, 18, 0.58);
    transition: 0.3s;
  }

  &__Field {
    margin-bottom: 15px;
    &::v-deep {
      .q-field--with-bottom {
        padding-bottom: 0;
      }

      .q-field--auto-height .q-field__control {
        background: #e5edf5;
        border-bottom: 1px solid rgba(1, 72, 116, 0.18);
        padding: 0 8px;
      }

      .q-field--filled.q-field--highlighted .q-field__control:before {
        opacity: 0;
      }

      .q-field--filled .q-field__control:after {
        height: 0;
      }

      .q-field--focused {
        &.q-field--filled .q-field__control {
          background: white;
          border: 1px solid #0148742e;
        }
      }

      .q-field--filled .q-field__control {
        background: #e5edf5;
        // border-bottom: 1px solid rgba(1, 72, 116, 0.18);
      }
    }
  }

  &__FieldIcon {
    cursor: pointer;
  }

  &__TogglesBlock {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
  }
}
</style>
