<template>
  <v-row v-if="formState.ready" dense>
    <v-col>
      <v-form ref="form" data-cy="dlcForm">
        <v-row dense>
          <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="2" px-2>
              <v-card
                :elevation="item.affective ? 10 : 1"
                :data-cy="'columncard:' + item.key"
              >
                <v-card-title>
                  <span
                    :class="{
                      'accent--text text-h5': item.affective
                    }"
                  >
                    {{ item.title }}
                  </span>
                  <div v-if="item.affective">
                    <v-icon color="accent">$ayiFilter</v-icon>
                    <v-icon color="accent">$ayiSort</v-icon>
                  </div>
                </v-card-title>

                <v-card-text>
                  <!-- INCLUDE CONTROL -->
                  <!-- {{ item }} -->
                  <v-switch
                    v-if="!item.rid"
                    :ref="item.key"
                    v-model="item.include"
                    dense
                    :label="$ay.t('Include')"
                    @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 v-if="item.include" class="d-flex justify-space-between">
                    <v-btn icon @click="move('start', index)"
                      ><v-icon data-cy="movestart"
                        >$ayiStepBackward</v-icon
                      ></v-btn
                    >
                    <v-btn icon @click="move('left', index)"
                      ><v-icon>$ayiBackward</v-icon></v-btn
                    >
                    <v-btn icon @click="move('right', index)"
                      ><v-icon>$ayiForward</v-icon></v-btn
                    >
                    <v-btn icon @click="move('end', index)"
                      ><v-icon>$ayiStepForward</v-icon></v-btn
                    >
                  </div>
                </v-card-text>
              </v-card>
            </v-col>
          </template>
        </v-row>
      </v-form>
    </v-col>
  </v-row>
</template>
<script>
//
//  CUSTOMIZE A DATA GRID'S VISIBLE COLUMNS
//
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);
    }
  },
  data() {
    return {
      obj: {
        id: 0,
        concurrency: 0,
        userId: 0,
        listKey: null,
        columns: null,
        sort: null
      },
      dataListKey: undefined,
      hiddenAffectiveColumns: [],
      fieldDefinitions: [],
      editView: [],
      formState: {
        ready: false,
        dirty: false,
        valid: true,
        readOnly: false,
        loading: true,
        errorBoxMessage: undefined,
        appError: undefined,
        serverError: {}
      },
      rights: window.$gz.role.fullRightsObject()
    };
  },
  computed: {
    canSave: function() {
      return this.formState.valid && this.formState.dirty;
    },
    canDuplicate: function() {
      return this.formState.valid && !this.formState.dirty;
    }
  },
  watch: {
    formState: {
      handler: function(val) {
        if (this.formState.loading) {
          return;
        }
        const 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
    }
  },
  beforeDestroy() {
    window.$gz.eventBus.$off("menu-click", clickHandler);
  },
  async created() {
    const vm = this;
    try {
      vm.dataListKey = this.$route.params.dataListKey;
      if (this.$route.params.hiddenAffectiveColumns) {
        vm.hiddenAffectiveColumns = this.$route.params.hiddenAffectiveColumns;
      }
      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);
    }
  },
  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) {
      const 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) {
        this.formState.loading = true;
        const columnView = {
          userId: this.$store.state.userId,
          listKey: this.dataListKey,
          columns: JSON.stringify(generateColumnViewFromEditView(this)),
          sort: this.obj.sort //not set here, just keep existing one that was fetched when opened this form
        };
        window.$gz.form.deleteAllErrorBoxErrors(this);
        try {
          const res = await window.$gz.api.post(API_BASE_URL, columnView);
          this.formState.loading = false;
          if (res.error) {
            this.formState.serverError = res.error;
            window.$gz.form.setErrorBoxErrors(this);
          } else {
            this.obj = res.data;
            initWorkingView(this);
            window.$gz.form.setFormState({
              vm: this,
              dirty: false,
              valid: true
            });
          }
        } catch (error) {
          this.formState.loading = false;
          window.$gz.errorHandler.handleFormError(error, this);
        }
      }
    },
    async reset() {
      const vm = this;
      try {
        vm.formState.loading = true;
        window.$gz.form.deleteAllErrorBoxErrors(vm);
        const res = await window.$gz.api.remove(API_BASE_URL + vm.dataListKey);
        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) {
        window.$gz.form.setFormState({
          vm: vm,
          loading: false
        });
        window.$gz.errorHandler.handleFormError(error, vm);
      }
    }
  }
};

/////////////////////////////
//
//
function clickHandler(menuItem) {
  if (!menuItem) {
    return;
  }
  const 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) {
  const menuOptions = {
    isMain: false,
    readOnly: vm.formState.readOnly,
    icon: "$ayiColumns",
    title: "Columns",
    helpUrl: "ay-start-form-data-tables#column-selector",
    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();
  await populateFieldDefinitions(vm);
  await fetchTranslatedFieldNames(vm);
  await fetchColumnView(vm);
  initWorkingView(vm);
}

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

////////////////////
//
async function populateFieldDefinitions(vm) {
  const res = await window.$gz.api.get(
    "data-list/listfields?DataListKey=" + vm.dataListKey
  );
  if (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) {
  const columnKeys = [];
  for (let i = 0; i < vm.fieldDefinitions.length; i++) {
    const cm = vm.fieldDefinitions[i];
    if (!columnKeys.includes(cm.tKey)) {
      columnKeys.push(cm.tKey);
    }
    //get section names too if present
    if (cm.tKeySection != null && !columnKeys.includes(cm.tKeySection)) {
      columnKeys.push(cm.tKeySection);
    }
  }
  await window.$gz.translation.cacheTranslations(columnKeys);
}

/////////////////////////////////
//
//
async function fetchColumnView(vm) {
  const 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"
    );
  }
  const ret = [];
  const columns = JSON.parse(vm.obj.columns);
  //Pass 1, iterate the columns first
  for (let i = 0; i < columns.length; i++) {
    const fld = vm.fieldDefinitions.find(z => z.fieldKey == columns[i]);
    //there can be a column definition that doesn't exist due to updates or misconfiguration or other issues so ignore it if that's the case
    if (fld) {
      const o = {
        key: fld.fieldKey,
        title: null,
        include: true
      };
      if (fld.tKeySection != null) {
        o.title = vm.$ay.t(fld.tKeySection) + "." + vm.$ay.t(fld.tKey);
      } else {
        o.title = vm.$ay.t(fld.tKey);
      }
      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++) {
    const fld = vm.fieldDefinitions[i];
    if (null == ret.find(z => z.key == fld.fieldKey)) {
      //nope, so add it
      const o = {
        key: fld.fieldKey,
        title: null,
        include: false
      };
      if (fld.tKeySection != null) {
        o.title = vm.$ay.t(fld.tKeySection) + "." + vm.$ay.t(fld.tKey);
      } else {
        o.title = vm.$ay.t(fld.tKey);
      }
      if (fld.isRowId) {
        o.rid = true;
        o.include = true;
      }
      if (vm.hiddenAffectiveColumns.includes(fld.fieldKey)) {
        o.affective = true;
      }
      ret.push(o);
    }
  }
  vm.editView = ret;
}

//////////////////////////////////////////////////////////
//
// Convert editedList view to real list view and return
//
function generateColumnViewFromEditView(vm) {
  const ret = [];
  for (let i = 0; i < vm.editView.length; i++) {
    const ev = vm.editView[i];
    if (!ev.include) {
      continue;
    }
    ret.push(ev.key);
  }
  return ret;
}
</script>
