import { Component, Prop, Watch } from 'vue-property-decorator';
import { mixins } from 'vue-class-component';
import {
  ValidatedField,
  SubscriberWidget,
  WidgetWrapper,
  FormWidget,
} from '@devsun/form-generator/dist';
import BaseFias from '@components/m-address/components/basic/m-fias/index.vue';
import set from 'lodash/set';
import get from 'lodash/get';
import {
  AddressTO,
  RoomPartTO,
  AddressPartTO,
  HousePartTO,
  SteadPartTO,
  AddressType,
} from '@openapi/fias';
import { FiasAddressMap } from '@/types/fias';

@Component({
  components: {
    BaseFias,
    WidgetWrapper,
  },
})
export default class FiasAddress extends mixins(
  SubscriberWidget,
  ValidatedField,
  FormWidget
) {
  @Prop() fiasAddressMap: FiasAddressMap;
  @Prop({ default: false }) mandatoryApartment: boolean;
  @Prop({ default: false }) mandatoryStreet: boolean;
  @Prop({ default: false }) mandatoryHome: boolean;
  fiasId: string | null = null;
  fiasValue: string | null = null;
  fiasData: AddressTO | null = null;

  $refs!: {
    widget: WidgetWrapper;
  };

  @Watch('fiasValue')
  onFiasValueChange(address = ''): void {
    // @ts-ignore todo OPENAPI add "full" string to AddressTO
    const path = this.fiasAddressMap['full'];
    if (path) {
      this.$nextTick(() => {
        set(this.model, path, address || '');
      });
    }
  }

  @Watch('currentValue')
  onUpdateFiasId(fiasId: string): void {
    if (!fiasId) {
      this.fiasId = '';
    }
  }

  @Watch('fiasData', { deep: true })
  onFiasDataChange(data: AddressTO | any): void {
    // @ts-ignore todo vue d.ts for WidgetWrapper
    this.$refs.widget.inputEvents?.input(data.id ?? data.value ?? '');

    if (!this.fiasAddressMap || !Object.keys(this.fiasAddressMap).length)
      return;

    for (const entry of Object.entries(this.fiasAddressMap)) {
      const [key, path] = entry as [keyof FiasAddressMap, string];
      const value = data[key];

      if (!data.hasOwnProperty(key)) {
        this.deleteByPath(path);

        continue;
      }
      if (value.type === AddressType.ROOM) {
        this.handleRoom(path, value);
      }
      if (value.type === AddressType.ADDRESS) {
        this.handleAddress(path, value);
      }
      if (
        value.type === AddressType.HOUSE ||
        value.type === AddressType.STEAD
      ) {
        this.handleHouseAndStead(path, value);
      }
    }
  }

  private deleteByPath(path: string): void {
    const split = path.split('.');
    const lastPart = split.pop();
    const parent = get(this.model, split);
    if (lastPart && parent) {
      delete parent[lastPart];
    }
  }

  private handleRoom(path: string, value: RoomPartTO): void {
    set(this.model, path, value.flat);
  }

  private handleAddress(path: string, value: AddressPartTO): void {
    set(this.model, path, {
      code: value.id,
      content: value.type ? `${value.type} ${value.name}` : value.name,
    });
  }

  mounted() {
    if (this.currentValue) {
      this.fiasId = this.currentValue;
    }
  }

  private get currentValue(): string {
    return this.value.content.toString();
  }

  private handleHouseAndStead(
    path: string,
    value: HousePartTO | SteadPartTO
  ): void {
    set(this.model, path, {
      code: value.id,
      content: value.name,
    });
  }
}
