<template>
  <operation-dialog
    persistent
    sign
    ref="dialogAccountCreate"
    title="Создание сотрудника"
    :sub="titleStep"
    v-model="opened"
    width="700px"
    @hide="close"
  >
    <div v-if="currentStep === 0">
      Создание сотрудника было прервано. Продолжить?
    </div>
    <AccountBaseForm
      v-if="currentStep === 1"
      :person-data="personData"
      :can-change-ip-address="true"
      :submit-function="submitAccountStepFunction"
      :trigger-submit="triggerAccountStepSubmit"
      @validateForm="updateAccountStepValidateForm"
    />
    <AccountOrganizationsForm
      v-if="currentStep === 2"
      :account-data="organizationsData"
      :submit-function="submitOrganizationsStepFunction"
      :trigger-submit="triggerOrganizationsStepSubmit"
      @validateForm="updateOrganizationsStepValidateForm"
    />
    <AccountLoginForm
      v-if="currentStep === 3"
      :account-login="loginData"
      :submit-function="submitLoginStepFunction"
      :trigger-submit="triggerLoginStepSubmit"
      @validateForm="updateLoginStepValidateForm"
    />
    <AccountRolesForm
      v-if="currentStep === 4"
      :user-roles-ids="userRolesIds"
      :submit-function="submitRolesStepFunction"
      :trigger-submit="triggerRolesStepSubmit"
    />
    <template #left-actions-panel>
      <r-btn
        v-if="currentStep === 0"
        outline
        label="Начать с начала"
        color="primary"
        @click="removeDataInLocal"
      />
      <r-btn
        v-else
        outline
        :label="currentStep === 1 || showResultBlock ? 'Закрыть' : 'Назад'"
        :icon="
          currentStep === 1 || showResultBlock
            ? 'pgs-close'
            : 'keyboard_arrow_left'
        "
        color="primary"
        @click="stepToBack"
      />
    </template>
    <template #right-actions-panel>
      <r-btn
        v-if="currentStep === 0"
        outline
        label="Продолжить заполнение"
        color="primary"
        @click="loadDataInLocal"
      />
      <r-btn
        v-else-if="!showResultBlock"
        outline
        :label="currentStep === countSteps ? 'Сохранить' : 'Далее'"
        :icon="currentStep === countSteps ? 'pgs-save' : undefined"
        positive
        :disable="!validateForm"
        @click="submit"
      />
    </template>
    <template #process>
      <result-block
        header="Создание сотрудника"
        icon="pgs-document"
        type="info"
      />
    </template>
    <template #result>
      <result-block :header="resultMessage" :type="resultType" />
      <AccountFinishForm v-if="finishInfo" :info="finishInfo" />
    </template>
  </operation-dialog>
</template>

<script lang="ts">
import {
  Component,
  Prop,
  Vue,
  Watch,
  Mixins,
  Ref,
} from 'vue-property-decorator';
import { oidcClientComputed } from '@state/modules/oidc-client';
import ProcessStarter from '@/mixins/ProcessStarter';
import OperationDialog from '@/components/common/operation-dialog/index.vue';
import {
  PersonData,
  AccountOrganizationsData,
  AccountLogin,
  AccountRolesData,
  FinishInfo,
} from '@/recruits/components/accounts/utils/types';
import AccountBaseForm from '@/recruits/components/accounts/components/forms/AccountBaseForm.vue';
import AccountOrganizationsForm from '@/recruits/components/accounts/components/forms/AccountOrganizationsForm.vue';
import AccountLoginForm from '@/recruits/components/accounts/components/forms/AccountLoginForm.vue';
import AccountRolesForm from '@/recruits/components/accounts/components/forms/AccountRolesForm.vue';
import AccountFinishForm from '@/recruits/components/accounts/components/forms/AccountFinishForm.vue';
import { getWebsocketsMsg } from '@/services/websockets';
import get from 'lodash/get';

const oidcClientMixin = Vue.extend({
  computed: {
    ...oidcClientComputed,
  },
});

@Component({
  components: {
    AccountBaseForm,
    AccountOrganizationsForm,
    AccountLoginForm,
    AccountRolesForm,
    AccountFinishForm,
  },
})
export default class CreateAccountModal extends Mixins(
  ProcessStarter,
  oidcClientMixin
) {
  @Prop({ default: null }) showModalCreate: boolean;
  @Prop({ default: 'milBaseCreateAccountProcess' })
  declare processKey: string;

  @Ref('dialogAccountCreate') operationDialog: OperationDialog;

  opened = false;
  showResultBlock = false;
  resultType: 'positive' | 'negative' | '' = '';
  resultMessage = '';
  finishInfo: FinishInfo | null = null;

  countSteps = 4;
  currentStep = 1;

  get titleStep(): string {
    return `Шаг ${this.currentStep} из ${this.countSteps}`;
  }

  private stepToBack() {
    if (this.currentStep === 1 || this.showResultBlock) {
      this.close();
    } else {
      this.currentStep--;
    }
  }

  private close(): void {
    this.saveLocalData();
    this.$emit('close');
  }

  private saveLocalData() {
    if (
      (this.loginData ||
        this.organizationsData ||
        this.personData ||
        this.rolesData) &&
      !this.showResultBlock
    ) {
      localStorage.setItem(
        'createAccountInfo',
        JSON.stringify({
          credential: this.loginData,
          account: this.organizationsData,
          person: this.personData,
          roles: this.rolesData,
        })
      );
    }
  }

  get userRolesIds(): string[] {
    return this.rolesData?.rolesList || [];
  }

  removeDataInLocal(): void {
    localStorage.removeItem('createAccountInfo');
    this.currentStep = 1;
  }

  loadDataInLocal(): void {
    const oldCreateAccount = localStorage.getItem('createAccountInfo');
    if (oldCreateAccount) {
      const dataLocal = JSON.parse(oldCreateAccount);
      this.personData = (dataLocal?.person as PersonData) || null;
      this.organizationsData =
        (dataLocal?.account as AccountOrganizationsData) || null;
      this.loginData = (dataLocal?.credential as AccountLogin) || null;
      const roles: AccountRolesData | null = dataLocal.roles || null;
      if (roles) {
        this.rolesData = {
          rolesList: roles.rolesList.filter(
            (role) => !roles.removeRoles.includes(role)
          ),
          removeRoles: [],
        };
      }
      this.currentStep = 1;
    }
  }

  // for 1 step
  accountStepValidateForm = false;
  triggerAccountStepSubmit = 0;
  personData: PersonData | null = null;

  private updateAccountStepValidateForm(validateStatus: boolean): void {
    this.accountStepValidateForm = validateStatus;
  }

  submitAccountStepFunction(personData: PersonData): void {
    this.personData = personData;
    this.currentStep++;
  }

  // for 2 step
  organizationsStepValidateForm = false;
  triggerOrganizationsStepSubmit = 0;
  organizationsData: AccountOrganizationsData | null = null;

  private updateOrganizationsStepValidateForm(validateStatus: boolean): void {
    this.organizationsStepValidateForm = validateStatus;
  }

  submitOrganizationsStepFunction(
    organizationsData: AccountOrganizationsData
  ): void {
    this.organizationsData = organizationsData;
    this.currentStep++;
  }

  // for 3 step
  loginStepValidateForm = false;
  triggerLoginStepSubmit = 0;
  loginData: AccountLogin | null = null;

  private updateLoginStepValidateForm(validateStatus: boolean): void {
    this.loginStepValidateForm = validateStatus;
  }

  submitLoginStepFunction(loginData: AccountLogin): void {
    this.loginData = loginData;
    this.currentStep++;
  }

  // for 4 step
  triggerRolesStepSubmit = 0;
  rolesData: AccountRolesData | null = null;

  submitRolesStepFunction(rolesData: AccountRolesData): void {
    this.rolesData = rolesData;
    this.finishCreateModal();
  }

  get validateForm(): boolean {
    switch (this.currentStep) {
      case 1:
        return this.accountStepValidateForm;
      case 2:
        return this.organizationsStepValidateForm;
      case 3:
        return this.loginStepValidateForm;
      case 4:
        return true;
      default:
        return false;
    }
  }

  private submit(): void {
    switch (this.currentStep) {
      case 1:
        this.triggerAccountStepSubmit++;
        break;
      case 2:
        this.triggerOrganizationsStepSubmit++;
        break;
      case 3:
        this.triggerLoginStepSubmit++;
        break;
      case 4:
        this.triggerRolesStepSubmit++;
        break;
    }
  }

  private async finishCreateModal(): Promise<void> {
    if (!this.personData) {
      this.$q.notify({
        message: 'Незаполнен шаг - перс. данные',
        color: 'negative',
      });
      this.currentStep = 1;
      return;
    }
    if (!this.organizationsData) {
      this.$q.notify({
        message: 'Незаполнен шаг - учетная запись',
        color: 'negative',
      });
      this.currentStep = 2;
      return;
    }
    if (!this.loginData) {
      this.$q.notify({
        message: 'Незаполнен шаг - логин',
        color: 'negative',
      });
      this.currentStep = 3;
      return;
    }
    this.operationDialog.toProcess();

    const dataObject: {
      account: AccountOrganizationsData;
      person: PersonData;
      credential: AccountLogin;
      roles: AccountRolesData;
    } = {
      credential: this.loginData,
      account: this.organizationsData,
      person: this.personData,
      roles: this.rolesData || { rolesList: [], removeRoles: [] },
    };

    try {
      const traceId = await this.startProcess(dataObject);

      this.showResultBlock = true;

      this.registerListener((message, removeListener) => {
        if (traceId !== message.traceId) return;
        if (message?.body?.type === 'finish') {
          this.resultType = 'positive';
          this.resultMessage = 'Сотрудник успешно добавлен в систему';
          this.finishInfo = {
            userName: get(message, 'body.userName', ''),
            password: get(message, 'body.value', ''),
            recoverLink: get(message, 'body.secretLink', ''),
          };
          removeListener();
          this.operationDialog.toResult();
          localStorage.removeItem('createAccountInfo');
          this.loginData = null;
          this.personData = null;
          this.organizationsData = null;
          this.rolesData = null;
        }

        if (message?.body?.type === 'error') {
          this.finishInfo = null;
          // get т.к. message для данной формы уникальный и содержит поле stepName
          const errorStepName = get(message, 'body.stepName');
          // если пришло название шага, то откатывает степпер
          if (errorStepName) {
            switch (errorStepName) {
              case 'credential':
                this.currentStep = 3;
                break;
              case 'account':
                this.currentStep = 2;
                break;
              case 'person':
                this.currentStep = 1;
                break;
            }
            this.operationDialog.reset();
            this.showResultBlock = false;
          } else {
            // если не пришло название шага, то мы показываем экран toResult
            this.resultType = 'negative';
            // get т.к. message может быть Task | PushMessage, а в Task нет поля msg
            this.resultMessage = getWebsocketsMsg(get(message, 'body.msg'));
            removeListener();
            this.operationDialog.toResult();
            localStorage.setItem(
              'createAccountInfo',
              JSON.stringify({
                credential: this.loginData,
                account: this.organizationsData,
                person: this.personData,
                roles: this.rolesData,
              })
            );
          }
        }
      });
    } catch (error: any) {
      this.resultType = 'negative';
      this.$q.notify({
        message: error.message,
        color: 'negative',
      });
      this.operationDialog.toResult();
    }
  }

  @Watch('showModalCreate')
  private async showModalCreateHandler(): Promise<void> {
    this.operationDialog.reset();
    this.opened = false;
    this.showResultBlock = false;
    this.resultMessage = '';
    this.resultType = '';
    this.currentStep = 1;
    this.loginData = null;
    this.personData = null;
    this.organizationsData = null;
    this.rolesData = null;
    if (this.showModalCreate) {
      this.opened = true;
      if (localStorage.getItem('createAccountInfo')) {
        this.currentStep = 0;
      }
    }
  }

  mounted(): void {
    window.addEventListener('beforeunload', () => {
      this.saveLocalData();
    });
  }

  beforeDestroy(): void {
    window.removeEventListener('beforeunload', () => {
      this.saveLocalData();
    });
  }
}
</script>
