import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import { QForm } from 'quasar';
import {
  Address,
  AddressSource,
  BaseAddressFormsBasicModel,
  House,
  Room,
  Stead,
} from '@interfaces/base/Fias';
import { v4 } from 'uuid';
import { AddressType, APIV2Api as FiasApi } from '@openapi/fias';
import { APIV2Api as AddressApi } from '@openapi/address';
import get from 'lodash/get';

const fiasApi = new FiasApi();
const addressApi = new AddressApi();

@Component({})
export default class BaseAddress extends Vue {
  @Prop() private id!: string | any;
  @Prop() private mandatoryStreet!: boolean;
  @Prop({ default: true }) private required: boolean;
  private model: BaseAddressFormsBasicModel | any = {
    city: null,
    district: null,
    house: null,
    locality: null,
    region: null,
    room: null,
    settlement: null,
    stead: null,
    street: null,
    source: null,
  };

  public async createAddress(): Promise<string> {
    return new Promise((resolve, reject) => {
      const data: any = {
        ...this.model,
        id: v4(),
        type: this.type,
      };
      try {
        addressApi.createAddress(data).then(() => {
          resolve(data.id);
        });
      } catch (e) {
        reject(e);
      }
    });
  }

  @Watch('id', { immediate: true })
  private idHandler(val: string | any): void {
    if (val) {
      // this.$q.loading.show();

      this.searchAddress(val)
        .then((address) => {
          this.parseAddressObject(address);
        })
        .finally(() => {
          this.$q.loading.hide();
        });
    }
  }

  @Watch('model', { deep: true })
  private modelHandler(): void {
    (this.$refs.form as QForm).resetValidation();
  }

  private get type(): AddressType {
    if (get(this.model, 'stead.number')) {
      return AddressType.STEAD;
    }

    if (get(this.model, 'room.room')) {
      return AddressType.ROOM;
    }

    if (get(this.model, 'house.number')) {
      return AddressType.HOUSE;
    }

    return AddressType.ADDRESS;
  }

  private created(): void {
    this.init();
  }

  private init(): void {
    this.model.city = this.initAddressObject();
    this.model.district = this.initAddressObject();
    this.model.house = this.initHouse();
    this.model.locality = this.initAddressObject();
    this.model.region = this.initAddressObject();
    this.model.room = this.initRoom();
    this.model.settlement = this.initAddressObject();
    this.model.stead = this.initStead();
    this.model.street = this.initAddressObject();
  }

  private async submitForm() {
    return await (this.$refs.form as QForm).validate();
  }

  private initAddressObject(): Address {
    return {
      id: v4(),
      name: '',
    };
  }

  private initHouse(): House {
    return {
      block: '',
      id: v4(),
      number: '',
      structure: '',
    };
  }

  private initRoom(): Room {
    return {
      flat: '',
      id: v4(),
      room: '',
    };
  }

  private initStead(): Stead {
    return {
      id: v4(),
      number: '',
    };
  }

  private parseAddressObject(address: BaseAddressFormsBasicModel): void {
    // We'll use this later to decide whether a field is required or not
    this.model.source = this.isFiasAddress(address) ? 'FIAS' : 'Custom';

    // If field exists
    if (get(address, 'region.name')) {
      // If it is a part of FIAS address user should not be able to modify it
      this.model.region.disabled = this.isFiasAddress(address);
      this.model.region.name = address?.region?.name;
    }

    if (get(address, 'district.name')) {
      this.model.district.disabled = this.isFiasAddress(address);
      this.model.district.name = address?.district?.name;
    }

    if (get(address, 'city.name')) {
      this.model.city.disabled = this.isFiasAddress(address);
      this.model.city.name = address?.city?.name;
    }

    if (get(address, 'locality.name')) {
      this.model.locality.disabled = this.isFiasAddress(address);
      this.model.locality.name = address?.locality?.name;
      this.model.locality.type = address?.locality?.type;
    }

    if (get(address, 'settlement.name')) {
      this.model.settlement.disabled = this.isFiasAddress(address);
      this.model.settlement.name = address?.settlement?.name;
    }

    if (get(address, 'street.name')) {
      this.model.street.disabled = this.isFiasAddress(address);
      this.model.street.name = address?.street?.name;
    }

    if (get(address, 'house.number')) {
      this.model.house.numberDisabled = this.isFiasAddress(address);
      this.model.house.number = address?.house?.number;
    }

    if (get(address, 'house.structure')) {
      this.model.house.structureDisabled = this.isFiasAddress(address);
      this.model.house.structure = address?.house?.structure;
    }

    if (get(address, 'house.block')) {
      this.model.house.blockDisabled = this.isFiasAddress(address);
      this.model.house.block = address?.house?.block;
    }

    if (get(address, 'room.flat')) {
      this.model.room.flatDisabled = this.isFiasAddress(address);
      this.model.room.flat = address?.room?.flat;
    }

    if (get(address, 'room.room')) {
      this.model.room.roomDisabled = this.isFiasAddress(address);
      this.model.room.room = address?.room?.room;
    }

    if (get(address, 'stead.number')) {
      this.model.stead.disabled = this.isFiasAddress(address);
      this.model.stead.number = address?.stead?.number;
    }
  }

  private requiredHendler(val: string): boolean | string {
    return val.length > 0 || 'Поле обязательно для заполнения';
  }

  private get cityRequired(): boolean {
    // It's sufficient ot have at least one of the following [city, locality, settlement]
    return (
      !this.model.city.name &&
      !this.model.locality.name &&
      !this.model.settlement.name
    );
  }

  private get houseRequired(): boolean {
    if (this.model.stead) {
      return false;
    }
    return !this.model.house.number && !this.model.room && !this.model.stead;
  }

  private isFiasAddress(address: BaseAddressFormsBasicModel): boolean {
    return address.source === AddressSource.Fias;
  }

  private async searchAddress(id: string): Promise<BaseAddressFormsBasicModel> {
    return new Promise((resolve, reject) => {
      let address: BaseAddressFormsBasicModel;

      // This is our internal address search
      try {
        addressApi
          .getAddress(id)
          .then(async ({ data }) => {
            if (data) {
              address = data;
            }
            // We want to track the origin of the address to decide later on
            // whether we allow user to change or override the address
          })
          .finally(async () => {
            if (address) {
              return resolve({
                ...address,
                source: AddressSource.Custom,
              });
            }

            // If we have not found address in our database, then perform global FIAS search

            const result = await fiasApi.searchById(id).catch((e) => reject(e));
            if (!result) return reject();

            if (address) {
              return resolve({
                ...result.data,
                source: AddressSource.Fias,
              });
            }
          });
      } catch (e) {
        // some code here...
      }
    });
  }
}
