<script>
import {castId, keyBy, objCopy, isEmpty} from "../utils";
import forEach from "lodash-es/forEach";
import isEqual from "lodash-es/isEqual";
import axios from "axios";

export default {
  props: ['object', 'schema', 'objects'],
  name: "EditObjectForm",
  data() {
    let object = this.object;

    const model = this.schema.obj_models.find((m) => m.id === object.model);
    let properties = this.schema.prop_models.filter((m) => m.object === model.id);
    let relations = this.schema.rel_models.filter((m) => m.object === model.id);

    properties.sort((a, b) => a.name.localeCompare(b.name));
    relations.sort((a, b) => a.name.localeCompare(b.name));

    let values = {};
    properties.forEach((p) => {
      let existing = object.values[p.id] || [];

      if (existing.length) {
          values[p.id] = existing;
      } else {
        if (p.optional) {
          values[p.id] = [];
        } else {
          values[p.id] = [
            // this is the format used for values
            {
              // it can also have model: ... here
              value: objCopy(p.default)
            }
          ];
        }
      }
    });

    properties = keyBy(properties, 'id');
    relations = keyBy(relations, 'id');

    let model_names = {};
    this.schema.obj_models.forEach((m) => {
      model_names[m.id] = m.name;
    });

    return {
      model,
      properties,
      relations,
      haveRelations: !isEmpty(relations),
      model_names,
      values,
      name: object.name,
      relationRefs: [],
    }
  },
  methods: {
    /** Get values in the raw format without grouping */
    collectData() {
      if (isEmpty(this.name)) {
        throw new Error("Name is required");
      }

      let values = [];
      forEach(objCopy(this.values), (vv, prop_model_id) => {
        for (let v of vv) {
          if (isEqual(v.value, {"String": ""}) && this.properties[prop_model_id].optional) {
            continue;
          }

          v.model = castId(prop_model_id);
          values.push(v);
        }
      })

      let relations = [];
      for (let rref of this.relationRefs) {
        for (let r of rref.collectData()) {
          relations.push(r);
        }
      }

      return {
        model: this.object.model, // string is fine
        id: this.object.id,
        values,
        relations,
      };
    },

    trySave() {
      let data;
      try {
        data = this.collectData();
      } catch (e) {
        alert(e.message);
        return;
      }
      console.log('Try save', data);

      axios({
        method: 'post',
        url: `/object/update/${this.object.id}`,
        data: data
      })
      .then((response) => {
        location.href = `/object/detail/${this.object.id}`;
      })
      .catch((error) => {
        // TODO show error toast instead
        alert(error.response ?
            error.response.data :
            error)
      });
    },

    setRelationRef(el) {
      if (el) {
        this.relationRefs.push(el)
      }
    },
  },
  beforeUpdate() {
    this.relationRefs = []
  },
  mounted() {
    this.$el.parentNode
        .classList.add('EditForm');
  }
}
</script>

<template>
  <div class="container">
    <div class="cols">
      <div class="col col-9">
        <h1>Edit {{ model.name }}</h1>
      </div>
      <div class="col col-3 text-right">
        <button type="button" @click="trySave" class="btn btn-primary">
          <i class="icon icon-check"></i>Save
        </button>
      </div>
    </div>
  </div>

  <div class="form-horizontal container">
    <edit-property v-for="(property, pi) in properties" :model="property" :values="values[property.id]" :key="pi"></edit-property>
  </div>

  <div v-if="haveRelations">
    <h3>Relations</h3>

    <edit-relation
        v-for="relation in relations"
        :ref="setRelationRef"
        :model_id="relation.id"
        :objects="objects"
        :initialInstances="object.relations[relation.id]"
        :schema="schema"
    ></edit-relation>
  </div>
</template>
