<template>
  <section class="account-edit-page">
    <div
      class="flex justify-start 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="$router.push({ name: 'personalAccounts' })"
      />
      <span class="text-h5"
        >{{ personModel.id ? 'Редактирование' : 'Создание' }} личного дела</span
      >
    </div>
    <div class="q-gutter-y-sm bg-white q-pa-md q-mt-md q-mx-md rounded-borders">
      <q-stepper
        v-model="step"
        vertical
        color="primary"
        animated
        flat
        :header-nav="true"
        class="q-gutter-y-md"
      >
        <q-step
          :name="1"
          title="Основные данные"
          icon="person"
          class="q-gutter-y-sm"
        >
          <FormGeneratorWrapper
            ref="formGeneratorWrapper"
            :mode="formMode"
            :schema="personSchema || {}"
            :model="personModel"
            :hide-nulls="true"
          />

          <q-stepper-navigation>
            <q-btn @click="step++" color="primary" label="Продолжить" />
          </q-stepper-navigation>
        </q-step>

        <q-step
          :name="2"
          title="Документы"
          icon="create_new_folder"
          class="q-gutter-y-sm"
        >
          <FormGeneratorWrapper
            ref="formGeneratorWrapper"
            mode="create"
            :schema="docsSchema"
            :model="docsModel"
            :hide-nulls="true"
          ></FormGeneratorWrapper>

          <span v-if="!Object.values(docsModel).flat().length"
            >Документы не найдены</span
          >

          <q-dialog v-model="deleteDialog.visible">
            <q-card class="q-pa-md">
              <q-card-section>Точно удалить?</q-card-section>
              <q-card-actions align="right">
                <q-btn @click="deleteDialog.reject" outline color="negative"
                  >Отмена</q-btn
                >
                <q-btn @click="deleteDialog.resolve" color="negative"
                  >Удалить</q-btn
                >
              </q-card-actions>
            </q-card>
          </q-dialog>

          <q-stepper-navigation>
            <q-btn
              @click="step--"
              color="secondary"
              label="Назад"
              class="q-mr-md"
            />
            <q-btn
              @click="step++"
              color="primary"
              label="Продолжить"
              class="q-mr-md"
            />

            <q-btn-dropdown color="primary" label="Добавить...">
              <q-list>
                <q-item
                  v-for="item in docsSchema &&
                  docsSchema.groupList &&
                  docsSchema.groupList
                    .filter(
                      (it) =>
                        ['ResidencePermition', 'ForeignPassport'].includes(
                          it.name
                        ) ||
                        (it.name === 'InternationalPassportRF' &&
                          (!docsModel.InternationalPassportRF ||
                            docsModel.InternationalPassportRF.length < 2)) ||
                        docsModel[it.name] === undefined ||
                        docsModel[it.name].length === 0
                    )
                    .sort((a, b) => (a.label > b.label ? 1 : -1))"
                  clickable
                  v-close-popup
                  @click="addDocument(item)"
                  :key="item.name"
                >
                  <q-item-section>
                    <q-item-label>{{ item.label }}</q-item-label>
                  </q-item-section>
                </q-item>
              </q-list>
            </q-btn-dropdown>
          </q-stepper-navigation>
        </q-step>

        <q-step
          :name="3"
          title="Адреса"
          icon="assignment"
          class="address-data q-gutter-y-sm"
        >
          <FormGeneratorWrapper
            ref="formGeneratorWrapper"
            mode="create"
            :schema="addressSchema || {}"
            :model="addressModel"
            :hide-nulls="true"
          ></FormGeneratorWrapper>

          <q-stepper-navigation>
            <q-btn
              @click="step--"
              color="secondary"
              label="Назад"
              class="q-mr-md"
            />
            <q-btn
              @click="step++"
              color="primary"
              label="Продолжить"
              class="q-mr-md"
            />
          </q-stepper-navigation>
        </q-step>

        <q-step :name="4" title="Контакты" icon="phone" class="q-gutter-y-sm">
          <FormGeneratorWrapper
            ref="formGeneratorWrapper"
            mode="create"
            :schema="contactsSchema || {}"
            :model="contactsModel"
            :hide-nulls="true"
          ></FormGeneratorWrapper>

          <q-stepper-navigation>
            <q-btn
              @click="step--"
              color="secondary"
              label="Назад"
              class="q-mr-md"
            />
            <q-btn
              @click="step++"
              color="primary"
              label="Продолжить"
              class="q-mr-md"
            />
          </q-stepper-navigation>
        </q-step>

        <q-step
          :name="5"
          title="Платежная информация"
          icon="account_balance"
          class="q-gutter-y-sm"
        >
          <FormGeneratorWrapper
            ref="formGeneratorWrapper"
            mode="create"
            :schema="paymentSchema || {}"
            :model="paymentModel"
            :hide-nulls="true"
          ></FormGeneratorWrapper>

          <q-stepper-navigation>
            <q-btn
              @click="step--"
              color="secondary"
              label="Назад"
              class="q-mr-md"
            />
          </q-stepper-navigation>
        </q-step>

        <!-- do not remove. it breaks quasar rendering for some reason -->
        <q-step :name="0" title="" class="display-none"></q-step>
      </q-stepper>
      <q-btn @click="save" color="primary" label="Сохранить" />
      <div class="q-pa-md"></div>
    </div>
  </section>
</template>

<script lang="ts">
import { Component, Watch } from 'vue-property-decorator';
import Vue from 'vue';
import FormGeneratorWrapper from '@/components/common/node-generator/FormGeneratorWrapper.vue';
import { notifyError, notifySuccess } from '@/utils/notify';
import {
  Person,
  PersonalAccountApi,
  PersonStatusEnum,
} from '@openapi/personal-accounts';
import { pushRoute } from '@/utils/routes';
import { ExtendedPerson } from '@/interfaces/services/personal-accounts';
import { isEmpty, omit } from 'lodash';
import { noop } from 'vue-class-component/lib/util';

interface GroupListI {
  name: string;
  num: number;
  label: string;
  hideLabel: boolean;
  attrList: string[];
}

interface AttrListI {
  name: string;
  label: string;
  type: string;
  view: string;
  hidden: boolean;
  readOnly: boolean;
}

type SchemaT = {
  id: string;
  modified: string;
  schema: 'Form';
  name: string;
  groupList: GroupListI[];
  attrList: AttrListI[];
};

type AddressT = {
  id: string;
  fullAddress: string;
  address: string;
  fiasCode: string;
  status: StatusRuT;
  addressType: string;
};

interface DocumentModel {
  id?: string;
  documentType?: string;
  series: string;
  number: string;
  dateFrom: string | null;
  issuer: string;
  departmentCode: string;
  dateTo: string | null;
  deleteBtn: number;
  status: string;
  [key: string]: string | number | null | undefined;
}

// type DocumentT =
//   | 'PasportRF'
//   | 'ResidencePermition'
//   | 'InternationalPassportRF'
//   | 'BirthСertificate'
//   | 'ForeignPassport'
//   | 'TemporaryIdentityCardRF'
//   | 'DrivingLicenseRF'
//   | 'MilitaryPassport'
//   | 'SailorPassport'
//   | 'SovietPassport'
//   | 'SoldierID'
//   | 'ReleaseCertificate'
//   | 'PassportLossCertificate'
//   | 'Form9Certificate'

type StatusRuT =
  | 'Не подтверждено'
  | 'Не актуальный'
  | 'Актуальный'
  | 'Ошибочный';
type StatusEngT = 'NOT_CONFIRMED' | 'NOT_RELEVANT' | 'RELEVANT' | 'WRONG';

{
  let skipWatcher = false;
  var watcherStep = function (this: any, _: any, b: number) {
    this.checkValidation(b);

    if (skipWatcher) {
      skipWatcher = false;
      return;
    }

    if (this.isFormValid === false) {
      this.step = b;
      skipWatcher = true;
    }
  };
}

const statusMap = {
  'Не подтверждено': 'NOT_CONFIRMED',
  'Не актуальный': 'NOT_RELEVANT',
  Актуальный: 'RELEVANT',
  Ошибочный: 'WRONG',
  NOT_CONFIRMED: 'Не подтверждено',
  NOT_RELEVANT: 'Не актуальный',
  RELEVANT: 'Актуальный',
  WRONG: 'Ошибочный',
} as any;

const personalAccountApi = new PersonalAccountApi();

const stupidApi = {
  getPerson(id: string): Promise<ExtendedPerson> {
    return personalAccountApi
      .getPerson(
        id,
        'contactdata,paymentdata,personaddress,personapplication,persondocument'
      )
      .then((it) => it.data);
  },
};

@Component({
  components: {
    FormGeneratorWrapper,
  },
})
export default class PersonalAccounts extends Vue {
  $refs: {
    formGeneratorWrapper: any;
  };

  personSchema: SchemaT | Record<string, never> = {};
  personModel = {
    id: '',
    firstName: '',
    lastName: '',
    middleName: '',
    snils: '',
    birthday: undefined,
    deathDate: undefined,
    citizenship: null,
    gender: null,
    inn: '',
    status: PersonStatusEnum.NotConfirmed,
    magicAllowEdit: '0',
  };

  docsSchema: SchemaT | Record<string, never> = {};
  docsModel: Record<string, DocumentModel[]> = {};

  addressSchema: SchemaT | Record<string, never> = {};
  addressModel = {
    RegistrationAddress: {} as AddressT & { RegistrationAddress: string },
    ActualResidenceAddress: {} as AddressT & { ActualResidenceAddress: string },
    TemporaryRegistrationAddress: {} as AddressT & {
      TemporaryRegistrationAddress: string;
    },
    BirthAddress: {} as AddressT & { BirthAddress: string },
  };

  contactsSchema: SchemaT | Record<string, never> = {};
  contactsModel = {
    Phone: [] as { Phone: string; status: StatusRuT; deleteBtn: number }[],
    Email: [] as { Email: string; status: StatusRuT; deleteBtn: number }[],
  };

  paymentSchema: SchemaT | Record<string, never> = {};
  paymentModel = {
    default: [] as {
      id: string;
      bic: string;
      bank: string;
      corrAcc: string;
      accNumber: string;
      status: string;
      deleteBtn: number;
    }[],
  };

  isFormValid = false;
  step = 1;

  deleteDialog: {
    visible: boolean;
    resolve(value: unknown): void;
    reject(value: unknown): void;
  } = {
    visible: false,
    resolve: noop,
    reject: noop,
  };

  get formMode(): string {
    return [
      PersonStatusEnum.New,
      PersonStatusEnum.Draft,
      PersonStatusEnum.NotConfirmed,
    ].includes(this.personModel.status)
      ? 'edit'
      : 'create';
  }

  @Watch('docsModel', { deep: true })
  watcherDoc(): void {
    Object.entries(this.docsModel).some(([key, listOfModels]) => {
      const index = listOfModels.findIndex((it: any) => it.deleteBtn);

      if (index === -1) {
        return false;
      }

      // #todo> send delete api if editing
      const promise = new Promise((resolve, reject) => {
        this.deleteDialog.resolve = resolve;
        this.deleteDialog.reject = reject;
        this.deleteDialog.visible = true;
      });

      promise
        .then(
          () => {
            this.rmDockument(key, listOfModels, index);
          },
          () => {
            listOfModels[index].deleteBtn = 0;
          }
        )
        .finally(() => {
          this.deleteDialog.visible = false;
        });

      return true;
    });
  }

  @Watch('step')
  watcherStep = watcherStep;

  checkValidation(step = this.step) {
    if (step === 2) {
      const els = document.querySelectorAll('.form-generator.qqq');

      this.isFormValid = [...els].every((it: any) => {
        it.__vue__?.validate();
        return !it.__vue__.$v.$invalid;
      });
      return;
    }

    this.$refs.formGeneratorWrapper?.$refs?.formGenerator?.validate();
    this.isFormValid = !this.$refs.formGeneratorWrapper?.$refs?.formGenerator
      ?.$v?.$invalid;
  }

  async addDocument(arg: GroupListI): Promise<void> {
    const standardModel: DocumentModel = {
      series: '',
      number: '',
      dateFrom: null,
      issuer: '',
      departmentCode: '',
      dateTo: null,
      deleteBtn: 0,
      status: 'Не подтверждено',
    };
    const attribute = this.docsSchema.attrList.find(
      (it) => it.name === arg.attrList[0]
    );
    const newAttribute = Object.assign({}, attribute, {
      name: arg.name + `[${arg.attrList.length}]`,
      hideLabel: false,
    });
    this.docsSchema.attrList.push(newAttribute);
    arg.attrList.push(newAttribute.name);

    if (this.docsModel[arg.name]) {
      const documentExist = this.docsModel[arg.name].find((itm) => {
        return (
          standardModel.series === itm.series &&
          standardModel.number === itm.number
        );
      }, false);
      if (documentExist) {
        Object.keys(documentExist).forEach((key) => {
          documentExist[key] = standardModel[key];
        });
        this.docsModel[arg.name].push(standardModel);
      }
    } else {
      this.$set(this.docsModel, arg.name, [standardModel]);
    }
  }

  rmDockument(dockumentName: string, docs: DocumentModel[], index: number) {
    docs.splice(index, 1);
    if (docs.length === 0) {
      delete this.docsModel[dockumentName];
    }
  }

  async save(): Promise<void> {
    this.checkValidation();

    if (!this.isFormValid) {
      return;
    }

    const documents = Object.entries(this.docsModel).flatMap(([key, val]) => {
      return val.flatMap((it) => {
        if (!it.series) {
          return [];
        }

        return Object.assign({}, it, {
          documentType: key,
          status: statusMap[it.status],
          deleteBtn: undefined,
        });
      });
    });

    const addresses = Object.entries(this.addressModel).flatMap(
      ([key, val]) => {
        if (!val.fullAddress) return [];
        return Object.assign({}, val, {
          addressType: key,
          status: statusMap[val.status],
          address: val.fullAddress,
          [key]: undefined,
          deleteBtn: undefined,
        });
      }
    );

    const contacts = Object.entries(this.contactsModel).flatMap(
      ([key, val]: any) => {
        return val.map((it: any) =>
          Object.assign({}, it, {
            contactType: key,
            status: statusMap[it.status],
            contact:
              (it.Phone && '+' + it.Phone.replace(/[^0-9]/g, '')) || it.Email,
            deleteBtn: undefined,
          })
        );
      }
    );

    const paymentsData = this.paymentModel.default.map((it: any) => {
      return Object.assign({}, it, {
        status: statusMap[it.status],
      });
    });
    const person: Person = {
      schema: 'Person',
      firstName: this.personModel.firstName,
      lastName: this.personModel.lastName,
      middleName: this.personModel.middleName,
      birthday: this.personModel.birthday,
      deathDate: this.personModel.deathDate,
      gender: this.personModel.gender || null,
      inn: this.personModel.inn,
      status: PersonStatusEnum.Reviewing,
      fullName: `${this.personModel.firstName} ${this.personModel.middleName} ${this.personModel.lastName}`,
      citizenship: this.personModel.citizenship || null,
      snils: this.personModel.snils.replace(/[^0-9]/g, ''),
      id: this.personModel.id || undefined,
    };

    (person.id
      ? personalAccountApi.updatePersonalAccount({
          person,
          documents,
          addresses: addresses as any,
          contacts,
          paymentsData,
        })
      : personalAccountApi.savePerson({
          person,
          documents,
          addresses: addresses as any,
          contacts,
          paymentsData,
        })
    ).then(
      ({ data }) => {
        const [id] = data.objectIds || [];
        if (id) {
          pushRoute(this.$router, {
            name: 'cards',
            params: {
              id: id,
              path: `personal-accounts`,
            },
            query: {
              components: this.$store.getters[
                'cardComponents/personalAccounts/components'
              ],
              active: 'personal',
            },
          });
          notifySuccess('Сохранено!');
        }
      },
      (it) => {
        notifyError(
          it?.response?.data?.message || 'Не удалось сохранить изменения'
        );
      }
    );
  }

  async fetchData(): Promise<void> {
    let account;

    try {
      account = await stupidApi.getPerson(this.$route.params.id);
    } catch (err) {
      notifyError('Личное дело не найдено');
      return;
    }

    console.log('ACCOUNT', Object.values(account));

    Object.assign(this.personModel, account, {
      magicAllowEdit: Object.values(account)
        .filter((it) => it !== '')
        .join(' '),
    });

    this.contactsModel.Phone.length = 0;
    this.contactsModel.Email.length = 0;
    account.contactdata?.forEach((it: any) => {
      const parsed = Object.assign({}, it, {
        status: statusMap[it.status],
        forbidDelete: true,
      });
      const prop = parsed.documentType || parsed.contactType;

      if ((this.contactsModel as any)[prop]) {
        (this.contactsModel as any)[prop].push(parsed);
      } else {
        this.$set(this.contactsModel, prop, [parsed]);
      }
    });

    this.paymentModel.default.length = 0;
    account.paymentdata?.forEach((it: any) => {
      this.paymentModel.default.push(
        Object.assign({}, it, {
          status: statusMap[it.status],
          forbidDelete: true,
        })
      );
    });

    account.personaddress?.forEach((it: any) => {
      const parsed = Object.assign({}, it, {
        status: statusMap[it.status],
        forbidDelete: true,
      });
      const prop = parsed.documentType || parsed.addressType;
      this.$set(this.addressModel, prop, parsed);
    });

    account.persondocument?.forEach((it: any) => {
      const parsed = Object.assign({}, it, {
        status: statusMap[it.status],
        forbidDelete: true,
      });
      const prop = parsed.documentType;
      if (this.docsModel[prop]) {
        this.docsModel[prop].push(parsed);
      } else {
        this.$set(this.docsModel, prop, [parsed]);
      }
    });
  }

  async fetchSchemas(): Promise<void> {
    const schemasFetched = {
      personSchema: import('@/constants/forms/PersonalAccountMain.json').then(
        (it) => it.default
      ) as Promise<SchemaT>,
      docsSchema: import(
        '@/constants/forms/PersonalAccountDocuments.json'
      ).then((it) => it.default) as Promise<SchemaT>,
      addressSchema: import(
        '@/constants/forms/PersonalAccountAddress.json'
      ).then((it) => it.default) as Promise<SchemaT>,
      contactsSchema: import(
        '@/constants/forms/PersonalAccountContacts.json'
      ).then((it) => it.default) as Promise<SchemaT>,
      paymentSchema: import(
        '@/constants/forms/PersonalAccountPayment.json'
      ).then((it) => it.default) as Promise<SchemaT>,
    };

    const schemasPromise = Promise.all(
      Object.entries(schemasFetched).map(async ([a, b]) => [a, await b])
    ).then((it) => Object.fromEntries(it)) as Promise<
      Record<keyof typeof schemasFetched, SchemaT>
    >;

    const schemas = await schemasPromise;

    Object.assign(this, schemas);
  }

  async mounted(): Promise<void> {
    await this.fetchSchemas();

    if (this.$route.params.id) {
      await this.fetchData();
    } else {
      Object.assign(this.personModel, this.$route.query);
    }
    // Инициализируем первый документ
    const pasportRF = this.docsSchema.groupList.find(
      ({ name }) => name === 'PasportRF'
    );
    if (pasportRF && isEmpty(this.docsModel?.PasportRF)) {
      this.addDocument(pasportRF);
    }
  }
}
</script>

<style>
.lightgray {
  background-color: rgba(0, 0, 0, 0.05);
}

.display-none {
  display: none;
}

.address-data .fias:not(#\0) {
  padding-bottom: 0;
}

.address-data .q-validation-component:not(#\0) {
  padding-bottom: 0;
}

.account-edit-page .q-checkbox:not(#\0) {
  margin-left: 0 !important;
}
</style>
