<script setup>
import { computed, watch, nextTick, ref, markRaw, useAttrs } from "vue";
import { VDataTable } from "vuetify/components/VDataTable";
import { clone } from "lodash-es";
import { useGraphqlModel } from "../../composables/graphqlModel";
import { useApiModel } from "../../composables/apiModel";
import { usePerPagePreference } from "../../composables/perPagePreference";
import { useDialog } from "../../composables/dialog";
import { useUserPermission } from "../../composables/userPermission";
import { useModelAutoRefresh } from "../../composables/modelAutoRefresh";
import { useState } from "#imports";
defineOptions({
  inheritAttrs: false
});
const props = defineProps({
  title: { type: String, required: true },
  noDataText: { type: String, required: false, default: "\u0E44\u0E21\u0E48\u0E1E\u0E1A\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25" },
  dialogWidth: { type: [String, Number], required: false },
  dialogMaxWidth: { type: [String, Number], required: false },
  dialogHeight: { type: [String, Number], required: false },
  dialogMaxHeight: { type: [String, Number], required: false },
  dialogFullscreen: { type: Boolean, required: false, default: false },
  initialData: { type: Object, required: false },
  toolbarColor: { type: String, required: false, default: "primary" },
  importable: { type: Boolean, required: false, default: true },
  exportable: { type: Boolean, required: false, default: true },
  insertable: { type: Boolean, required: false, default: true },
  searchable: { type: Boolean, required: false, default: true },
  search: { type: String, required: false },
  saveAndStay: { type: Boolean, required: false, default: false },
  stringFields: { type: Array, required: false, default: () => [] },
  onlyOwnerEdit: { type: Boolean, required: false, default: false },
  onlyOwnerOverridePermission: { type: [String, Array], required: false },
  api: { type: Boolean, required: false, default: false },
  perPageStorageKey: { type: String, required: false },
  perPageStorageEnabled: { type: Boolean, required: false, default: true },
  autoRefresh: { type: [Number, Boolean], required: false, default: false },
  autoRefreshDefault: { type: Number, required: false, default: 60 },
  autoRefreshControl: { type: Boolean, required: false, default: true },
  modelName: { type: String, required: true },
  modelKey: { type: String, required: false, default: "id" },
  modelBy: { type: Object, required: false, default: void 0 },
  operationCreate: { type: [Object, String], required: false },
  operationUpdate: { type: [Object, String], required: false },
  operationDelete: { type: [Object, String], required: false },
  operationRead: { type: [Object, String], required: false },
  operationReadPageable: { type: [Object, String], required: false },
  operationSearch: { type: [Object, String], required: false },
  fields: { type: Array, required: false, default: () => [] },
  headers: { type: Array, required: false }
});
const emit = defineEmits(["open:dialog", "close:dialog", "create", "update", "delete"]);
const attrs = useAttrs();
const plainAttrs = computed(() => {
  const returnAttrs = clone(attrs);
  if (props.headers) returnAttrs["headers"] = props.headers;
  return returnAttrs;
});
const authenState = useState("authentication");
const currentUsername = computed(() => {
  let userProfile = authenState.value?.userProfile;
  return userProfile?.username ?? "";
});
const currentItem = ref(void 0);
const isDialogOpen = ref(false);
const isDialogReadonly = ref(false);
const itemsPerPageInternal = ref();
usePerPagePreference(itemsPerPageInternal, {
  storageKey: props.perPageStorageKey ?? props.modelName,
  enabled: props.perPageStorageEnabled
});
const {
  items,
  itemsLength,
  search,
  setSearch,
  canServerPageable,
  canServerSearch,
  canCreate,
  canUpdate,
  canDelete,
  createItem,
  importItems,
  updateItem,
  deleteItem,
  loadItems,
  reload,
  isLoading
} = props.api ? useApiModel(props) : useGraphqlModel(props);
const { autoRefresh, manualReload } = useModelAutoRefresh(props, {
  reload,
  isLoading,
  isDialogOpen
});
function openDialog(item) {
  isDialogReadonly.value = false;
  currentItem.value = item;
  nextTick(() => {
    isDialogOpen.value = true;
    emit("open:dialog", item);
  });
}
function openDialogReadonly(item) {
  isDialogReadonly.value = true;
  currentItem.value = item;
  nextTick(() => {
    isDialogOpen.value = true;
    emit("open:dialog", item);
  });
}
async function confirmDeleteItem(item, callback) {
  let confirm = await useDialog().confirm({ message: "Do you want to delete record?" });
  if (confirm) onDeleteItem(item, callback);
}
const onCreateItem = (item, callback) => {
  createItem(item, callback).then(() => {
    emit("create", item, callback);
  });
};
const onUpdateItem = (item, callback) => {
  updateItem(item, callback).then(() => {
    emit("update", item, callback);
  });
};
const onDeleteItem = (item, callback) => {
  deleteItem(item, callback).then(() => {
    emit("delete", item, callback);
  });
};
const canEditRow = function(item) {
  if (props.onlyOwnerEdit) {
    if (item?.userstampField?.createdBy && item?.userstampField?.createdBy == currentUsername.value) return true;
    if (!!props.onlyOwnerOverridePermission && useUserPermission().check(props.onlyOwnerOverridePermission)) return true;
    return !item?.userstampField?.createdBy;
  }
  return true;
};
const operation = ref({ openDialog, openDialogReadonly, createItem, importItems, updateItem, deleteItem, reload, setSearch, canServerPageable, canServerSearch, canCreate, canUpdate, canDelete, canEditRow, onlyOwnerEdit: props.onlyOwnerEdit, onlyOwnerOverridePermission: props.onlyOwnerOverridePermission, autoRefresh: markRaw(autoRefresh) });
const computedInitialData = computed(() => {
  return Object.assign({}, props.initialData, props.modelBy);
});
watch(() => props.search, () => {
  search.value = props.search;
}, { immediate: true });
defineExpose({ reload, operation, items, autoRefresh });
</script>

<template>
  <v-card>
    <slot
      name="header"
      :items="items"
      :operation="operation"
    >
      <VToolbar :color="toolbarColor">
        <v-row
          justify="end"
          class="ma-1"
          density="compact"
          no-gutters
          align="center"
        >
          <v-col cols="7">
            <VToolbarTitle class="pl-3">
              <slot
                name="title"
                :reload="manualReload"
              >
                {{ title }}
                <v-icon
                  size="small"
                  @click="manualReload"
                >
                  mdi mdi-refresh
                </v-icon>
              </slot>
              <slot
                name="autoRefreshControl"
                v-bind="autoRefresh"
              >
                <ModelAutoRefreshChip
                  v-if="props.autoRefreshControl"
                  :control="autoRefresh"
                  :color="toolbarColor"
                />
              </slot>
            </VToolbarTitle>
          </v-col>
          <v-col cols="5">
            <slot name="search" :items="items" :operation="operation" v-if="props.searchable">
              <VTextField
                v-model="search"
                class="justify-end w-100"
                density="compact"
                hide-details
                placeholder="ค้นหา"
                clearable
                variant="solo"
              />
            </slot>
          </v-col>
        </v-row>

        <VToolbarItems>
          <slot name="toolbarItems" :items="items" :operation="operation"/>
          <ImportCSV
            v-if="props.importable && canCreate && props.insertable"
            icon="mdi mdi-file-upload"
            variant="flat"
            :color="toolbarColor"
            :stringFields="props.stringFields"
            @import="importItems"
          />
          <ExportCSV
            v-if="props.exportable && items.length"
            icon="mdi mdi-file-download"
            variant="flat"
            :file-name="title"
            :model-value="items"
            :color="toolbarColor"
            :stringFields="props.stringFields"
          />
          <VBtn
            v-if="canCreate && props.insertable"
            :color="toolbarColor"
            prepend-icon="mdi mdi-plus"
            variant="flat"
            @click="openDialog()"
          >
            add
          </VBtn>
        </VToolbarItems>
      </VToolbar>
    </slot>
    <v-data-table-server
      v-if="canServerPageable"
      v-bind="plainAttrs"
      v-model:items-per-page="itemsPerPageInternal"
      color="primary"
      :items="items"
      :items-length="itemsLength"
      :item-value="props.modelKey"
      :search="search"
      :loading="isLoading"
      @update:options="loadItems"
    >
      <!-- @ts-ignore -->
      <template
        v-for="(_, name, index) in $slots"
        :key="index"
        #[name]="slotData"
      >
        <slot
          :name="name"
          v-bind="slotData || {}"
          :operation="operation"
        />
      </template>
      <template
        v-if="!$slots['item.action']"
        #item.action="{ item }"
      >
        <v-btn
            v-if="!canUpdate || !canEditRow(item)"
            variant="flat"
            density="compact"
            icon="mdi mdi-note-search"
            @click="openDialogReadonly(item)"
        />
        <v-btn
          v-if="canUpdate && canEditRow(item)"
          variant="flat"
          density="compact"
          icon="mdi mdi-note-edit"
          @click="openDialog(item)"
        />
        <v-btn
          v-if="canDelete && canEditRow(item)"
          variant="flat"
          density="compact"
          icon="mdi mdi-delete"
          @click="confirmDeleteItem(item)"
        />
      </template>
    </v-data-table-server>
    <v-data-table
      v-else
      v-bind="plainAttrs"
      v-model:items-per-page="itemsPerPageInternal"
      color="primary"
      :items="items"
      :item-value="props.modelKey"
      :search="search"
      :loading="isLoading"
    >
      <!-- @ts-ignore -->
      <template
        v-for="(_, name, index) in $slots"
        :key="index"
        #[name]="slotData"
      >
        <slot
          :name="name"
          v-bind="slotData || {}"
          :operation="operation"
        />
      </template>
      <template
        v-if="!$slots['item.action']"
        #item.action="{ item }"
      >
        <v-btn
            v-if="!canUpdate || !canEditRow(item)"
            variant="flat"
            density="compact"
            icon="mdi mdi-note-search"
            @click="openDialogReadonly(item)"
        />
        <v-btn
            v-if="canUpdate && canEditRow(item)"
            variant="flat"
            density="compact"
            icon="mdi mdi-note-edit"
            @click="openDialog(item)"
        />
        <v-btn
            v-if="canDelete && canEditRow(item)"
            variant="flat"
            density="compact"
            icon="mdi mdi-delete"
            @click="confirmDeleteItem(item)"
        />
      </template>
    </v-data-table>
    <FormDialog
      v-model="isDialogOpen"
      :title="title"
      :fullscreen="dialogFullscreen"
      :initial-data="computedInitialData"
      :form-data="currentItem"
      @create="onCreateItem"
      @update="onUpdateItem"
      @afterLeave="emit('close:dialog')"
      :saveAndStay="saveAndStay"
      :readonly="isDialogReadonly"
      :width="dialogWidth"
      :height="dialogHeight"
      :max-width="dialogMaxWidth"
      :max-height="dialogMaxHeight"
    >
      <template #default="slotData">
        <slot
          name="form"
          :tableItems="items"
          :tableOperation="operation"
          v-bind="slotData"
        />
      </template>
      <template #title="slotData">
        <slot
            name="formTitle"
            :tableItems="items"
            :tableOperation="operation"
            v-bind="slotData"
        />
      </template>
      <template #action="slotData">
        <slot
            name="formAction"
            :tableItems="items"
            :tableOperation="operation"
            v-bind="slotData"
        />
      </template>
    </FormDialog>
  </v-card>
</template>
