<template>
  <div :ready="isReady">
    <MicroWsFormGenerator
      ref="formGenerator"
      v-if="showGenerator"
      :schema="adoptedSchema"
      :binder="binder"
      :model="model"
      :root-model="rootModelData"
      :attractions="attractions"
      :hide-nulls="hideNulls"
      :padded-groups="paddedGroups"
      :isCreate="!isEdit && !isPreview"
      :isEdit="isEdit"
      :form-options="formOptions"
      :isPreview="isPreview"
      :index="index"
      :level="level"
      :reset-attractions.sync="resetFGAttractions"
      :importer="$GlobalComponentImporter"
      @ready="setReadyAttr"
      @update="update"
      @valid="onValidation"
    />
  </div>
</template>

<script lang="ts">
import { Component, Vue, Prop, Watch, PropSync } from 'vue-property-decorator';
import { Attractions, Model, Schema } from '@devsun/eva-models';
import {
  DataBinder,
  MicroWsFormGenerator,
  ObjectMetaSchema,
  ObjectMetaSchemaParser,
  FormMode,
  convertObjSchemaResponse,
} from '@devsun/form-generator/dist';
import { FormGeneratorProps, FormGenerator } from '@devsun/form-generator';
import get from 'lodash/get';

@Component({
  components: {
    MicroWsFormGenerator,
  },
})
export default class FormGeneratorWrapper extends Vue {
  @Prop({ required: true }) model!: Model.Base;
  @Prop({ required: true }) schema!: Schema.MetaClassSchemaRaw;

  // todo remove
  @Prop({ default: false }) hideNulls!: boolean;
  @Prop({ default: false }) paddedGroups!: boolean;

  @Prop({ default: 'preview' }) mode!: FormMode;
  @Prop() formOptions: FormGeneratorProps | undefined;
  @Prop() attractionCode: string | undefined;

  @Prop({}) index?: number;
  @Prop({}) level: number;

  @PropSync('resetAttractions', { default: false })
  resetFGAttractions?: boolean;

  $refs!: {
    formGenerator: FormGenerator;
  };

  update(model: Model.Base) {
    let notEmpty = model && Object.keys(model).length > 0;
    if (notEmpty) {
      this.$emit('update', model);
    }
  }

  isValid: boolean = true;
  // attractions: Attractions.Attractions | undefined;
  attractions: Attractions.Attractions | null = null;

  rawSchema: ObjectMetaSchema = {
    fields: [],
    groups: [],
  };
  localModel: Model.Base | undefined;
  adoptedSchema: ObjectMetaSchema = {
    fields: [],
    groups: [],
  };
  binder: DataBinder = new DataBinder();

  get showGenerator(): boolean {
    if (this.schema.requiresEnhancedSchema && this.attractionCode) {
      return Boolean(this.hasSchema && this.attractions);
    }

    return this.hasSchema;
  }

  get isPreview() {
    return this.mode === 'preview';
  }

  get isCreate() {
    return this.mode === 'create';
  }

  get isEdit() {
    return this.mode === 'edit';
  }

  get closestFormGenerator() {
    let parent = this.$parent;

    while (parent) {
      // @ts-ignore
      if (parent.IS_FORM_GENERATOR) {
        return parent;
      }

      parent = parent.$parent;
    }
  }

  get rootModelData(): Model.Base {
    return this.closestFormGenerator
      ? get(this.closestFormGenerator, `$props.rootModel`)
      : this.model;
  }

  created() {
    this.localModel = this.model;
    this.setAttractions();
    this.setSchema(this.schema);
    /*
    todo request schema
    fix circular dependencies
    await SchemaService.getInstance(ref).getObjSchema({ref: formRef, guid: formGuid});
    */
  }

  @Watch('schema', { immediate: false })
  schemaHandler(newSchema: Schema.MetaClassSchemaRaw) {
    this.setSchema(newSchema);
    if (!this.attractions) {
      this.setAttractions();
    }
  }

  onValidation(isValid: boolean) {
    console.log('[FGW][onValidation]', isValid);
    this.$emit('update-validation', isValid);
  }

  setSchema(schema: Schema.MetaClassSchemaRaw) {
    const converted = convertObjSchemaResponse(schema);
    this.rawSchema = ObjectMetaSchemaParser.parseRawSchema(
      // TODO: тут происходит мутация пропсы schema
      converted,
      this.mode
    );
    this.adoptedSchema = this.getAdoptedSchema(this.rawSchema);
  }

  get hasSchema() {
    return (
      this.adoptedSchema &&
      (this.adoptedSchema.groups.length > 0 ||
        this.adoptedSchema.fields.length > 0)
    );
  }

  async setAttractions() {
    if (this.schema.requiresEnhancedSchema && this.attractionCode) {
      // bff attractions - backend/mock-api/resources/enhanced-settings
      await this.$store
        .dispatch(
          'utils/components/fetchAttractionsByCode',
          this.attractionCode
        )
        .then((attractions) => {
          this.attractions = attractions;
        });
    } else if (this.schema.extensions) {
      // built-in schema attractions
      this.attractions = this.schema.extensions;
    }
  }

  getAdoptedSchema(rawSchema: ObjectMetaSchema): ObjectMetaSchema {
    const result: ObjectMetaSchema = {
      schema: rawSchema.schema,
      fields: [],
      groups: rawSchema.rootGroups || [],
    };

    console.warn('[FGW] get adoptedSchema', result);
    return result;
  }

  isReady = false;

  setReadyAttr() {
    this.isReady = true;
  }

  triggerValidate() {
    // @ts-ignore TODO d.ts for form-generator
    return this.$refs.formGenerator.validate();
  }
}
</script>
