<template>
  <div>
    <v-json-editor
      class="q-mb-sm"
      :key="key"
      v-model="json"
      :options="{
        mode,
        mainMenuBar: false,
        onValidationError: setSchemaErrors,
        onBlur: setLazySchemaErrors,
        onChange,
      }"
    />
    <transition-group appear name="fade">
      <q-banner
        v-for="(error, idx) of lazySchemaErrors"
        :key="'' + error + idx"
        inline-actions
        rounded
        class="bg-red-7 text-white q-mb-md"
      >
        <div
          :key="lineIndex"
          v-for="(line, lineIndex) of error.message.split('<br>')"
        >
          {{ line }}
        </div>
      </q-banner>
    </transition-group>
  </div>
</template>

<script lang="ts">
// @ts-ignore
import VJsonEditor from 'v-jsoneditor';
import { Component, Vue, Prop, Watch } from 'vue-property-decorator';
import isEqual from 'lodash/isEqual';
import cloneDeep from 'lodash/cloneDeep';

@Component({
  components: {
    VJsonEditor,
  },
})
export default class JsonEditorWithErrors extends Vue {
  @Prop() value: any;
  @Prop() shouldUpdateKey: boolean;
  @Prop({ default: 'code' }) mode: string;

  json: any = {};
  key: number = 0;

  lazySchemaErrors: any[] = [];
  liveSchemaErrors: any[] = [];

  @Watch('value', { immediate: true, deep: true })
  onValueChange(v: any) {
    if (!isEqual(v, this.json)) {
      this.json = v;
      if (this.shouldUpdateKey) {
        this.key++;
      }
    }
  }

  @Watch('mode')
  onModeChange() {
    if (this.shouldUpdateKey) {
      this.key++;
    }
  }

  setLazySchemaErrors() {
    this.lazySchemaErrors = this.liveSchemaErrors;
    if (!this.lazySchemaErrors.length) {
      this.$emit('blur', cloneDeep(this.json));
    }
  }

  setSchemaErrors(errors: any[]) {
    this.liveSchemaErrors = errors;
    if (this.lazySchemaErrors.length) {
      this.lazySchemaErrors = this.liveSchemaErrors;
    }
  }

  onChange() {
    this.$emit('input', this.json);
  }
}
</script>

<style scoped>
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.2s ease-in;
}
.fade-enter-to,
.fade-leave {
  opacity: 1;
}
.fade-enter,
.fade-leave-to {
  opacity: 0;
}
</style>