<template>
  <v-row v-if="formState.ready">
    <v-col>
      <v-form ref="form">
        <v-row>
          <gz-error :error-box-message="formState.errorBoxMessage"></gz-error>

          <template v-for="(item, index) in editView">
            <v-col :key="item.key" cols="12" sm="6" lg="4" xl="3" px-2>
              <v-card :data-cy="'columncard:' + item.key">
                <v-card-title>
                  {{ item.title }}
                </v-card-title>

                <v-card-text>
                  <!-- INCLUDE CONTROL -->
                  <!-- {{ item }} -->
                  <v-switch
                    v-if="!item.rid"
                    v-model="item.include"
                    :label="$ay.t('Include')"
                    :ref="item.key"
                    @change="includeChanged(item)"
                  ></v-switch>
                  <div v-if="item.rid" class="v-label mb-8 mt-6">
                    {{ $ay.t("Include") }}
                  </div>
                  <!-- RE-ORDER CONTROL -->
                  <div class="d-flex justify-space-between" v-if="item.include">
                    <v-btn large icon @click="move('start', index)"
                      ><v-icon large data-cy="movestart"
                        >$ayiStepBackward</v-icon
                      ></v-btn
                    >
                    <v-btn large icon @click="move('left', index)"
                      ><v-icon large>$ayiBackward</v-icon></v-btn
                    >
                    <v-btn large icon @click="move('right', index)"
                      ><v-icon large>$ayiForward</v-icon></v-btn
                    >
                    <v-btn large icon @click="move('end', index)"
                      ><v-icon large>$ayiStepForward</v-icon></v-btn
                    >
                  </div>
                </v-card-text>
              </v-card>
            </v-col>
          </template>
        </v-row>
      </v-form>
    </v-col>
  </v-row>
</template>
<script>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*  Xeslint-disable    */
////////////////////////////////////////////////////////////////////////////////////////////////////////////

const FORM_KEY = "ay-data-list-column-view";
const API_BASE_URL = "data-list-column-view/";

export default {
  async beforeRouteLeave(to, from, next) {
    if (!this.formState.dirty) {
      next();
      return;
    }
    if ((await window.$gz.dialog.confirmLeaveUnsaved()) === true) {
      next();
    } else {
      next(false);
    }
  },
  beforeDestroy() {
    window.$gz.eventBus.$off("menu-click", clickHandler);
  },
  async created() {
    let vm = this;
    try {
      vm.dataListKey = this.$route.params.dataListKey;
      await initForm(vm);
      vm.formState.ready = true;
      window.$gz.eventBus.$on("menu-click", clickHandler);
      generateMenu(vm);
      //init disable save button so it can be enabled only on edit to show dirty form
      window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":save");
      vm.formState.loading = false;
    } catch (err) {
      vm.formState.ready = true;
      window.$gz.errorHandler.handleFormError(err, vm);
    }
  },
  data() {
    return {
      obj: {
        id: 0,
        concurrency: 0,
        userId: 0,
        listKey: null,
        columns: null,
        sort: null
      },
      dataListKey: undefined,
      fieldDefinitions: [],
      editView: [],
      formState: {
        ready: false,
        dirty: false,
        valid: true,
        readOnly: false,
        loading: true,
        errorBoxMessage: undefined,
        appError: undefined,
        serverError: {}
      },
      rights: window.$gz.role.fullRightsObject()
    };
  },
  //WATCHERS
  watch: {
    formState: {
      handler: function(val) {
        //,oldval is available here too if necessary
        if (this.formState.loading) {
          return;
        }

        //enable / disable save button
        let canSave = val.dirty && val.valid && !val.readOnly;
        if (canSave) {
          window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":save");
        } else {
          window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":save");
        }
      },
      deep: true
    }
  },
  computed: {
    canSave: function() {
      return this.formState.valid && this.formState.dirty;
    },
    canDuplicate: function() {
      return this.formState.valid && !this.formState.dirty;
    }
  },
  methods: {
    enumSelectionList: function(enumKey) {
      return window.$gz.enums.getSelectionList(enumKey);
    },
    includeChanged: function(item) {
      if (item.required && item.visible == false) {
        item.required = false;
      }
      window.$gz.form.setFormState({
        vm: this,
        dirty: true
      });
    },
    move: function(direction, index) {
      let totalItems = this.editView.length;
      let newIndex = 0;
      //calculate new index
      switch (direction) {
        case "start":
          newIndex = 0;
          break;
        case "left":
          newIndex = index - 1;
          if (newIndex < 0) {
            newIndex = 0;
          }
          break;
        case "right":
          newIndex = index + 1;
          if (newIndex > totalItems - 1) {
            newIndex = totalItems - 1;
          }

          break;
        case "end":
          newIndex = totalItems - 1;
          break;
      }

      this.editView.splice(newIndex, 0, this.editView.splice(index, 1)[0]);
      window.$gz.form.setFormState({
        vm: this,
        dirty: true
      });
    },
    form() {
      return window.$gz.form;
    },
    fieldValueChanged(ref) {
      if (!this.formState.loading && !this.formState.readOnly) {
        window.$gz.form.fieldValueChanged(this, ref);
      }
    },
    async submit() {
      if (this.canSave) {
        let vm = this;

        vm.formState.loading = true;

        let url = API_BASE_URL;

        let columnView = {
          userId: vm.$store.state.userId,
          listKey: vm.dataListKey,
          columns: JSON.stringify(generateColumnViewFromEditView(vm)),
          sort: vm.obj.sort //not set here, just keep existing one that was fetched when opened this form
        };

        //clear any errors vm might be around from previous submit
        window.$gz.form.deleteAllErrorBoxErrors(this);
        try {
          let res = await window.$gz.api.post(url, columnView);

          vm.formState.loading = false;
          if (res.error) {
            vm.formState.serverError = res.error;
            window.$gz.form.setErrorBoxErrors(vm);
          } else {
            vm.obj = res.data;
            initWorkingView(vm);
            window.$gz.form.setFormState({
              vm: vm,
              dirty: false,
              valid: true
            });
          }
        } catch (error) {
          vm.formState.loading = false;
          window.$gz.errorHandler.handleFormError(error, vm);
        }
      }
    },
    async reset() {
      let vm = this;
      try {
        vm.formState.loading = true;

        let url = API_BASE_URL + vm.dataListKey;

        window.$gz.form.deleteAllErrorBoxErrors(vm);
        let res = await window.$gz.api.remove(url);

        if (res.error) {
          vm.formState.serverError = res.error;
          window.$gz.form.setErrorBoxErrors(vm);
        } else {
          //this "remove" route is a reset route and returns the object
          vm.obj = res.data;
          initWorkingView(vm);
          window.$gz.form.setFormState({
            vm: vm,
            dirty: false,
            valid: true
          });
        }
      } catch (error) {
        //Update the form status
        window.$gz.form.setFormState({
          vm: vm,
          loading: false
        });
        window.$gz.errorHandler.handleFormError(error, vm);
      }
    }
  }
};

/////////////////////////////
//
//
function clickHandler(menuItem) {
  if (!menuItem) {
    return;
  }
  let m = window.$gz.menu.parseMenuItem(menuItem);
  if (m.owner == FORM_KEY && !m.disabled) {
    switch (m.key) {
      case "save":
        m.vm.submit();
        break;
      case "reset":
        m.vm.reset();
        break;
      case "duplicate":
        m.vm.duplicate();
        break;
      default:
        window.$gz.eventBus.$emit(
          "notify-warning",
          FORM_KEY + "::context click: [" + m.key + "]"
        );
    }
  }
}

//////////////////////
//
//
function generateMenu(vm) {
  let menuOptions = {
    isMain: false,
    readOnly: vm.formState.readOnly,
    icon: "$ayiColumns",
    title: "Columns",
    helpUrl: "ay-data-list-column-view",
    formData: {
      ayaType: window.$gz.type.FormCustom,
      formCustomTemplateKey: undefined,
      recordName: vm.obj.name
    },
    menuItems: []
  };

  menuOptions.menuItems.push({
    title: "Save",
    icon: "$ayiSave",
    surface: true,
    key: FORM_KEY + ":save",
    vm: vm
  });

  menuOptions.menuItems.push({
    title: "ResetToDefault",
    icon: "$ayiUndo",
    surface: false,
    key: FORM_KEY + ":reset",
    vm: vm
  });

  window.$gz.eventBus.$emit("menu-change", menuOptions);
}

/////////////////////////////////
//
//
async function initForm(vm) {
  await fetchTranslatedText(vm);
  await populateFieldDefinitions(vm);
  await fetchTranslatedFieldNames(vm);
  await fetchColumnView(vm);
  initWorkingView(vm);
}

//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText(vm) {
  await window.$gz.translation.cacheTranslations([
    "ResetToDefault",
    "Columns",
    "Include"
  ]);
}

////////////////////
//
async function populateFieldDefinitions(vm) {
  //http://localhost:7575/api/v8/data-list/listfields?DataListKey=TestWidgetDataList
  let res = await window.$gz.api.get(
    "data-list/listfields?DataListKey=" + vm.dataListKey
  );
  if (res.error) {
    //throw new Error(res.error);
    throw new Error(window.$gz.errorHandler.errorToString(res, vm));
  } else {
    vm.fieldDefinitions = res.data;
  }
}

//////////////////////////////////////////////////////////
//
// Ensures column names are present in translation table
//
async function fetchTranslatedFieldNames(vm) {
  let columnKeys = [];
  for (let i = 0; i < vm.fieldDefinitions.length; i++) {
    let cm = vm.fieldDefinitions[i];
    columnKeys.push(cm.tKey);
  }

  await window.$gz.translation.cacheTranslations(columnKeys);
}

/////////////////////////////////
//
//
async function fetchColumnView(vm) {
  let res = await window.$gz.api.get(API_BASE_URL + vm.dataListKey);
  if (res.error) {
    throw new Error(window.$gz.errorHandler.errorToString(res, vm));
  } else {
    vm.obj = res.data;
  }
}

////////////////////
//
function initWorkingView(vm) {
  if (vm.fieldDefinitions == null) {
    throw new Error(
      "ay-data-list::initWorkingView - fieldDefinitions are not set"
    );
  }

  let ret = [];
  let columns = JSON.parse(vm.obj.columns);

  //Pass 1, iterate the columns first
  for (let i = 0; i < columns.length; i++) {
    //de-lodash
    //let fld = window.$gz. _.find(vm.fieldDefinitions, ["fieldKey", lvItem.fld]);
    let fld = vm.fieldDefinitions.find(z => z.fieldKey == columns[i]);
    let o = {
      key: fld.fieldKey,
      title: vm.$ay.t(fld.tKey),
      include: true
    };

    if (fld.isRowId) {
      o.rid = true;
    }

    ret.push(o);
  }

  //Pass 2, remaining fields not already dealt with
  for (let i = 0; i < vm.fieldDefinitions.length; i++) {
    let fld = vm.fieldDefinitions[i];

    if (null == ret.find(z => z.key == fld.fieldKey)) {
      //nope, so add it
      let o = {
        key: fld.fieldKey,
        title: vm.$ay.t(fld.tKey),
        include: false
      };

      if (fld.isRowId) {
        o.rid = true;
        o.include = true;
      }

      ret.push(o);
    }
  }
  vm.editView = ret;

  //eoc
}

//////////////////////////////////////////////////////////
//
// Convert editedList view to real list view and return
//
function generateColumnViewFromEditView(vm) {
  let ret = [];

  for (let i = 0; i < vm.editView.length; i++) {
    let ev = vm.editView[i];
    if (!ev.include) {
      continue;
    }
    ret.push(ev.key);
  }
  return ret;
  //eoc
}

/////////////END OF FORM//////////////////
</script>
