<template>
  <div class="ws-crud mx-auto">
    <WsCRUDTitlebar
      :label="label"
      :pageMode="pageMode"
      :modelName="modelName"
      @create-open="$_onCreateOpen()"
    >
      <template v-slot:btns>
        <WsBtn
          v-if="importRoute"
          :to="importRoute"
          minWidth="90px"
          color="textSecondary"
          outlined
        >
          <v-icon size="20">mdi-upload</v-icon>
          <div>匯入</div>
        </WsBtn>
      </template>
    </WsCRUDTitlebar>
    <v-card
      class="mt-6"
      elevation="1"
    >
      <WsCRUDFilter
        ref="filter"
        :searching.sync="searching"
        :orderBy.sync="C_orderBy"
        :orderWay.sync="C_orderWay"
      >
        <template v-slot:filterSelects>
          <WsStateSelect
            v-for="(filterSelect,filterSelectIndex) in filterSelects"
            :key="filterSelectIndex"
            :placeholder="filterSelect.placeholder"
            v-model="filters[filterSelect.name]"
            :items="filterSelect.items"
          ></WsStateSelect>
        </template>
      </WsCRUDFilter>
      <!-- Data Table -->
      <!-- <v-skeleton-loader
        v-if="modeldataLoading"
        type="table"
      ></v-skeleton-loader> -->
      <WsDataTable
        :loading="modeldataLoading"
        :inRowBtnComplete="inRowBtnComplete"
        :inRowBtnRead="inRowBtnRead"
        :inRowBtnUpdate="inRowBtnUpdate"
        :inRowBtnDelete="inRowBtnDelete"
        :rowClickRead="rowClickRead"
        :items="modelDatas"
        :itemsPerPage="itemsPerPage"
        :fields="fields"
        :displayFields="_displayFields"
        :headers="_tableHeaders"
        :pageMode="pageMode"
        :modelName="modelName"
        :dataTotalCount="dataTotalCount"
        :currentPage="currentPage"
        :lastPage="lastPage"
        :showExpand="showExpand"
        :sortBy="C_orderBy"
        :sortDesc="_sortDesc"
        @read="$_onRead($event)"
        @pageto="$_onPageto($event)"
        @update="$_onUpdate($event)"
        @delete="$_onDelete($event)"
        @complete="$_onComplete($event)"
        @sort-update="$_onSortUpdate($event)"
      />
    </v-card>
    <!-- Create Dialog -->
    <WsCreateDialog
      ref="createDialog"
      :label="label"
      :fields="_createFields"
      :modelName="modelName"
      :errorMessages="createErrorMessages"
      @create-submit="$_onCreateSubmit($event)"
    />
    <WsUpdateDialog
      ref="updateDialog"
      :label="label"
      :fields="_updateFields"
      :modelName="modelName"
      :errorMessages="updateErrorMessages"
      @update-submit="$_onUpdateSubmit($event)"
    />
    <!-- Read Dialog -->
    <WsReadDialog
      ref="readDialog"
      :fields="_displayFields"
      :titleKey="titleKey"
      @delete-submit="$_onReadDialogDeleteSubmit($event)"
      @update="$_onReadDialogUpdate($event)"
    />
    <!-- Delete Dialog -->
    <WsAlertDialog
      ref="deleteDialog"
      title="確定要刪除嗎？"
      description="刪除後資料將無法回覆"
      @submit="$_onDeleteSubmit($event)"
    />
    <!-- Complete Dialog -->
    <WsCompleteDialog
      ref="completeDialog"
      title="確定完成嗎？"
      @submit="$_onCompleteSubmit($event)"
    />
  </div>
</template>

<script>
import locales from "@/locales/zh_tw";
export default {
  data: () => ({
    isMounted: false,
    modeldataLoading: false,
    modelDatas: null,
    lastPage: 1,
    dataTotalCount: 0,
    currentPage: 1,
    searching: "",
    C_orderBy: "updated_at",
    C_orderWay: "desc",
    filters: {},
    createErrorMessages: null,
    updateErrorMessages: null,
  }),
  methods: {
    $_onSortUpdate($event) {
      this.C_orderBy = $event.sortBy[0];
      this.C_orderWay = $event.sortDesc[0] ? "desc" : "asc";
    },
    $_filterSelectsInit() {
      if (!this.filterSelects) {
        return;
      }
      this.filterSelects.forEach((filterSelect) => {
        const _value = filterSelect.items[0]
          ? filterSelect.items[0].value
          : null;
        this.$set(this.filters, filterSelect.name, _value);
      });
    },
    $_onPageto(page) {
      this.currentPage = page;
    },
    $_onReadDialogUpdate(item) {
      const tarModelData = this.modelDatas.find((e) => {
        return e.id == item.id;
      });
      this.$refs.readDialog.close();
      this.$refs.updateDialog.open(tarModelData);
    },
    $_modelDataUpdate(item) {
      const index = this.modelDatas.findIndex((e) => {
        return e.id == item.id;
      });
      if (index >= 0) {
        this.modelDatas.splice(index, 1);
        this.modelDatas.splice(index, 0, item);
      }
    },
    async $_onUpdateSubmit($event) {
      this.$refs.updateDialog.startLoading();
      try {
        await this.$axios.patch(`/${this.modelName}/${$event.id}`, $event);
        this.$refs.updateDialog.close();
        this.$_fetchData();
      } catch (error) {
        if (error && error.response) {
          if (error.response.data.message == "data store fail.") {
            alert("新增失敗");
          } else {
            this.updateErrorMessages = this.$_formatErrorMessages(
              error.response.data.message
            );
          }
        } else {
          alert("新增失敗");
        }
      } finally {
        this.$refs.updateDialog.stopLoading();
      }
    },
    $_onUpdate(item) {
      this.updateErrorMessages = null;
      const tarModelData = this.modelDatas.find((e) => {
        return e.id == item.id;
      });
      this.$refs.updateDialog.open(tarModelData);
    },
    $_removeModeldataById(id) {
      const index = this.modelDatas.findIndex((e) => {
        return e.id == id;
      });
      if (index >= 0) {
        this.modelDatas.splice(index, 1);
      }
    },
    async $_onDeleteSubmit($event) {
      this.$refs.deleteDialog.startLoading();
      try {
        await this.$axios.delete(`/${this.modelName}/${$event}`);
        this.$_removeModeldataById($event);
      } catch (error) {
        alert(error);
      } finally {
        this.$refs.deleteDialog.close();
      }
    },
    async $_onCompleteSubmit($event) {
      this.$refs.completeDialog.startLoading();
      try {
        await this.$axios.post(`/${this.modelName}/complete/${$event}`);
        this.$refs.completeDialog.close();
        this.$_fetchData();
      } catch (error) {
        alert(error);
      } finally {
        this.$refs.completeDialog.close();
      }
    },
    $_onComplete($event) {
      this.$refs.completeDialog.open($event.id);
    },
    $_onDelete($event) {
      this.$refs.deleteDialog.open($event.id);
    },
    $_formatErrorMessages(errorMessages) {
      const formeted_error_messages = {};
      for (let key in errorMessages) {
        const errorMessage = errorMessages[key][0];
        if (locales[errorMessage]) {
          formeted_error_messages[key] = locales[errorMessage];
        } else {
          formeted_error_messages[key] = errorMessage;
        }
      }
      return formeted_error_messages;
    },
    async $_onCreateSubmit($event) {
      this.$refs.createDialog.startLoading();
      try {
        const res = await this.$axios.post(`/${this.modelName}`, $event);
        this.modelDatas.unshift(res.data.data);
        this.$refs.createDialog.close();
      } catch (error) {
        if (error && error.response) {
          if (error.response.data.message == "data store fail.") {
            alert("新增失敗");
          } else {
            this.createErrorMessages = this.$_formatErrorMessages(
              error.response.data.message
            );
          }
        } else {
          alert("新增失敗");
        }
      } finally {
        this.$refs.createDialog.stopLoading();
      }
    },
    $_onCreateOpen() {
      this.createErrorMessages = null;
      this.$refs.createDialog.open();
    },
    async $_onReadDialogDeleteSubmit($event) {
      this.$refs.readDialog.deleteLoadingStart();
      try {
        await this.$axios.delete(`/${this.modelName}/${$event.id}`);
        this.$_removeModeldataById($event.id);
      } catch (error) {
        alert(error);
      } finally {
        this.$refs.readDialog.close();
      }
    },
    $_onRead($event) {
      this.$refs.readDialog.open($event);
    },
    async $_fetchData() {
      this.modeldataLoading = true;
      this.$store.dispatch("app/startPageLoading");
      try {
        const getUrl = `/${this.modelName}`;
        const params = {
          page: this.currentPage,
          search: this.searching,
          order_way: this.C_orderWay,
          order_by: this.C_orderBy,
          lang: this.$store.state.locale.selectingLocale,
        };
        for (let fieldKey in this.filters) {
          params[fieldKey] = this.filters[fieldKey];
        }
        const res = await this.$axios.get(getUrl, {
          params: params,
        });
        this.lastPage = res.data.meta.last_page;
        this.dataTotalCount = res.data.meta.total;
        this.modelDatas = res.data.data;
      } catch (error) {
        alert(error);
      } finally {
        this.modeldataLoading = false;
        this.$store.dispatch("app/stopPageLoading");
      }
    },
    $_dataInitFrompProps() {
      this.C_orderWay = this.orderWay;
      this.C_orderBy = this.orderBy;
    },
    $_dataInitFromQuery() {
      if (this._searchFromQuery) {
        this.searching = this._searchFromQuery;
      }
      if (this._pageFromQuery) {
        this.currentPage = this._pageFromQuery;
      }
      if (this._orderWayFromQuery) {
        this.C_orderWay = this._orderWayFromQuery;
      }
      if (this._orderByFromQuery) {
        this.C_orderBy = this._orderByFromQuery;
      }
    },
    $_routerUpdate() {
      if (
        this._pageFromQuery == this.currentPage &&
        this._orderByFromQuery == this.C_orderBy &&
        this._orderWayFromQuery == this.C_orderWay &&
        this._searchFromQuery == this.searching
      ) {
        return;
      }
      setTimeout(() => {
        this.$router.push({
          query: {
            ...this.$router.query,
            order_by: this.C_orderBy,
            order_way: this.C_orderWay,
            page: this.currentPage,
            search: this.searching,
          },
        });
      }, 0);
    },
    $_dataWatch() {
      this.$watch(
        (vm) =>
          [vm.C_orderBy, vm.C_orderWay, vm.currentPage, vm.searching].join(),
        () => {
          if (!this.isMounted) {
            return;
          }
          this.$_fetchData();
          this.$_routerUpdate();
        }
      );
    },
  },
  computed: {
    _sortDesc() {
      if (this.C_orderWay == "desc") {
        return true;
      } else {
        return false;
      }
    },
    _createFields() {
      return this.$_CMS_geUpdateFields(this.fields, this.createHideFields);
    },
    _updateFields() {
      return this.$_CMS_geUpdateFields(this.fields, this.updateHideFields);
    },
    _displayFields() {
      return this.$_CMS_getDisplayFields(this.fields);
    },
    _tableHeaders() {
      let _tableHeaders = [];
      this.showFields.forEach((showFieldKey) => {
        if (showFieldKey in this._displayFields) {
          const field = this._displayFields[showFieldKey];
          if (field.type == "list" || field.type == "evaluationStage") {
            return;
          }

          if (
            field.type == "image" ||
            field.type == "tags" ||
            field.type == "password" ||
            field.type == "link" ||
            field.type == "editor"
          ) {
            _tableHeaders.push({
              value: showFieldKey,
              text: field.label,
              width: field.width,
              sortable: false,
            });
            return;
          }

          _tableHeaders.push({
            value: showFieldKey,
            text: field.label,
            width: field.width,
            // sortable: false,
          });
        }
      });
      let actionWidth = 32;
      let count = 0;
      if (this.inRowBtnRead) {
        actionWidth += 40.1;
        count++;
      }
      if (this.inRowBtnUpdate) {
        actionWidth += 40.1;
        count++;
      }
      if (this.inRowBtnDelete) {
        actionWidth += 40.1;
        count++;
      }
      if (this.inRowBtnComplete) {
        actionWidth += 40.1;
        count++;
      }
      actionWidth += count * 8;
      _tableHeaders.push({
        text: "",
        value: "actions",
        width: `${actionWidth}px`,
        sortable: false,
        fixed: true,
      });
      return _tableHeaders;
    },
    _pageFromQuery() {
      return this.$route.query.page;
    },
    _orderByFromQuery() {
      return this.$route.query.order_by;
    },
    _orderWayFromQuery() {
      return this.$route.query.order_way;
    },
    _searchFromQuery() {
      return this.$route.query.search ? this.$route.query.search : "";
    },
    _orderValue() {
      return `order_by=${this.C_orderBy}&order_way=${this.C_orderWay}`;
    },
  },
  watch: {
    "$store.state.locale.selectingLocale": {
      handler() {
        this.$_fetchData();
      },
    },
    filters: {
      handler() {
        if (!this.isMounted) {
          return;
        }
        this.$_fetchData();
      },
      deep: true,
    },
    _orderValue: {
      handler() {
        if (!this.isMounted) {
          return;
        }
        this.currentPage = 1;
      },
    },
    searching: {
      handler() {
        if (!this.isMounted) {
          return;
        }
        this.currentPage = 1;
        this.$_fetchData();
        this.$_routerUpdate();
      },
    },
    _pageFromQuery: {
      handler() {
        if (this._pageFromQuery) {
          this.currentPage = this._pageFromQuery;
        }
      },
    },
    _orderByFromQuery: {
      handler() {
        if (this._orderByFromQuery) {
          this.C_orderBy = this._orderByFromQuery;
        }
      },
    },
    _orderWayFromQuery: {
      handler() {
        if (this._orderWayFromQuery) {
          this.C_orderWay = this._orderWayFromQuery;
        }
      },
    },
    _searchFromQuery: {
      handler() {
        if (this._searchFromQuery) {
          this.searching = this._searchFromQuery;
        }
      },
    },
  },
  mounted() {
    this.$_dataInitFrompProps();
    this.$_dataInitFromQuery();
    this.$_filterSelectsInit();
    this.$_fetchData();
    setTimeout(() => {
      this.isMounted = true;
      this.$_dataWatch();
    }, 0);
  },
  props: {
    inRowBtnComplete: {
      type: Boolean,
      default: false,
    },
    createHideFields: {
      type: Array,
      default: null,
    },
    updateHideFields: {
      type: Array,
      default: null,
    },
    rowClickRead: {
      type: Boolean,
      default: false,
    },
    filterSelects: {
      type: Array,
      default: null,
    },
    itemsPerPage: {
      type: Number,
      default: 15,
    },
    showExpand: {
      type: Boolean,
      default: true,
    },
    importRoute: {
      type: String,
      default: null,
    },
    pageMode: {
      type: Boolean,
      default: false,
    },
    titleKey: {
      type: String,
      default: "name",
    },
    showFields: {
      type: Array,
      required: true,
    },
    inRowBtnRead: {
      type: Boolean,
      default: true,
    },
    inRowBtnUpdate: {
      type: Boolean,
      default: true,
    },
    inRowBtnDelete: {
      type: Boolean,
      default: true,
    },
    orderBy: {
      type: [String, Array],
      default: "updated_at",
    },
    orderWay: {
      type: [String, Array],
      default: "desc",
    },
    liveSearching: {
      type: Boolean,
      default: false,
    },
    fields: {
      type: Object,
      required: true,
    },
    modelName: {
      type: String,
      default: null,
    },
    label: {
      type: String,
      default: null,
    },
  },
};
</script>

<style lang="scss">
@import "../assets/scss/ws-crud.scss";
</style>