<template>
  <div class="table-container clearfix">
    <Modal v-if="(rowsToDelete && rowsToDelete.length > 0) || this.deleteError" :danger="true" @close="closeDelete">
      <template #header>
        {{ t("ui.delete_model", {model: t(["models", definition.model, "name"].join("."))}) }}
      </template>
      <template #body>
        <div v-if="rowsToDelete.length > 1">
          {{ t("ui.delete_confirm_mulitple", {model: t(["models", definition.model, "name"].join("."), 2).toLowerCase()}) }}
          <ul class="enum">
            <li v-for="(rowToDelete, index) in rowsToDelete" :key="index">
              {{ rowToDelete.node_description }}
            </li>
          </ul>
        </div>
        <div v-if="rowsToDelete.length === 1">
          {{ t('ui.delete_confirm_one', rowsToDelete[0]) }}
        </div>
        <div v-if="deleteError" class="alert alert-danger" role="alert">
          {{ deleteError }}
        </div>
      </template>
      <template #footer>
        <button v-if="(rowsToDelete && rowsToDelete.length > 0)" type="button" class="btn btn-danger" @click="confirmDelete">
          {{ t("ui.delete") }}
        </button>
        <button type="button" class="btn btn-light" @click="closeDelete">
          {{ t("ui.cancel") }}
        </button>
      </template>
    </Modal>
    <div v-if="hasControlsTop" class="table-controls-top clearfix">
      <div class="toolbar">
        <slot name="actions" />
        <button v-if="selected.length > 0" type="button" class="btn btn-sm btn-danger" @click="rowsToDelete=selected">
          <i class="fa fa-times" />&nbsp;{{ t("ui.delete") }}
        </button>
      </div>
      <div class="table-default-actions">
        <div>
          <div class="d-inline-block">
            <button class="btn btn-sm btn-light dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" @click="getViewCounts = true">
              {{ react.selectedView.description }}
            </button>
            <div class="dropdown-menu">
              <div>
                <h6 class="dropdown-header">
                  {{ t('ui.quickviews') }}
                </h6>
              </div>
              <a v-for="(view, index) in views" :key="index" class="dropdown-item dropdown-item-sm" @click="react.selectedView = view; saveState()">{{ view.description }} <span class="badge rounded-pill bg-light text-dark float-end">{{ viewCount[index]}}</span></a>
            </div>
          </div>
          <div v-if="additionalColumns.length > 0" class="d-inline-block">
            <button class="btn btn-sm btn-light dropdown-toggle" type="button" data-bs-toggle="dropdown" >
              <i class="fa fa-list" />
            </button>
            <div class="dropdown-menu">
              <div>
                <h6 class="dropdown-header">
                  {{ t('ui.additional_columns') }}
                </h6>
              </div>
              <div v-for="(column, index) in additionalColumns" :key="index" class="dropdown-item dropdown-item-sm" @click="function(event){event.stopPropagation()}">
                <div class="form-check form-switch">
                  <input
                    :id="'additional-column-'+definition.model+'-'+(column.name ? column.name : column)"
                    type="checkbox"
                    class="form-check-input"
                    value="1"
                    :checked="isAdditionalColumnSelected(column.name ? column.name : column)"
                    @click="addAdditionalColumn(column.name ? column.name : column)">
                  <label class="form-check-label" :for="'additional-column-'+definition.model+'-'+(column.name ? column.name : column)">{{ react.managerColumns[column.name ? column.name : column].label }}</label>
                </div>
              </div>
            </div>
          </div>
          <div class="d-inline-block">
            <button class="btn btn-sm btn-light" type="button" @click="addCustomFilter">
              <i class="fa fa-filter" />
            </button>
          </div>
          <div class="d-inline-block">
            <input v-model="react.quickSearch" type="text" class="quick-search form-control form-control-sm" :placeholder="placeHolder()" size="50">
          </div>
          <div class="d-inline-block me-1">
            <a href="#" @click="confirmExportGraphql()">
              <i class="fa fa-arrow-alt-circle-down text-muted" />
            </a>
          </div>
          <div class="d-inline-block">
            <a href="#" @click="refetch()">
              <i class="fa fa-sync-alt text-muted" />
            </a>
          </div>
        </div>
      </div>
    </div>
    <div v-if="react.managerFilter[0].and_filters.length+react.managerFilter[0].or_filters.length > 0" class="table-filters">
      <div v-if="react.managerFilter[0].and_filters.length > 0" class="mb-1">
        <b class="me-1">{{t('ui.match_all_of')}}:</b>
        <a v-for="(custom_filter, index) in react.managerFilter[0].and_filters" :key="index" class="badge bg-light text-dark me-2" @click="removeCustomFilter(react.managerFilter[0].and_filters, index)">
          <b>{{t(['models', definition.model, 'fields', custom_filter.field.split("__")[0], 'name'].join('.'))}}</b>
          {{getCriteriaDesc("__"+custom_filter.field.split("__")[1]).toLowerCase()}}
          "<b>{{custom_filter.qs}}</b>"
          <i class="fa fa-times" />
        </a>
      </div>
      <div v-if="react.managerFilter[0].or_filters.length > 0" class="mb-1">
        <b class="me-1">{{t('ui.match_one_of')}}:</b>
        <a v-for="(custom_filter, index) in react.managerFilter[0].or_filters" :key="index" class="badge bg-light text-dark me-2" @click="removeCustomFilter(react.managerFilter[0].or_filters, index)">
          <b>{{t(['models', definition.model, 'fields', custom_filter.field.split("__")[0], 'name'].join('.'))}}</b>
          {{getCriteriaDesc("__"+custom_filter.field.split("__")[1]).toLowerCase()}}
          "<b>{{custom_filter.qs}}</b>"
          <i class="fa fa-times" />
        </a>
      </div>
    </div>
    <VeeForm ref="vee_form" v-slot="{handleSubmit}" as="div">
      <form ref="form" autocomplete="off" @submit.prevent="handleSubmit($event,exportGraphql)">
        <Modal v-if="showExportGraphql" @close="showExportGraphql = false">
          <template #header>
            {{ t('ui.export')}}
          </template>
          <template #body>
            <div class="form-group row">
              <label class="col-form-label col-sm-3">{{t('ui.filename')}}</label>
              <div class="col-sm-9">
                <VeeField v-model="exportGraphqlFileName" class="form-control" name="exportGraphqlFileName" :label="t('ui.filename')" :rules="{required:true}" />
              </div>
            </div>
          </template>
          <template #footer class="form-actions">
            <button type="submit" class="btn" :class="{'disabled btn-light': loading || rows.total_count > 999999, 'btn-primary': !loading && rows.total_count <= 999999}">
              <i class="fa fa-arrow-alt-circle-down" />
              {{t('ui.export')}}
            </button>
            <button type="button" class="btn btn-light" @click="showExportGraphql = false">{{t('ui.cancel')}}</button>
            <span v-if="!loading" :class="{'text-danger': rows.total_count > 999999}">
              {{t('ui.row_count', rows)}}
            </span>
            <span v-else class="dot-flashing ms-4" role="status" />
          </template>
        </Modal>
      </form>
    </VeeForm>
    <VeeForm ref="vee_form" v-slot="{ handleSubmit }" as="div">
      <form ref="form" autocomplete="off" @submit.prevent="handleSubmit($event, saveCustomFilter)">
        <Modal v-if="showAddCustomFilter" @close="hideAddCustomFilter">
          <template #header>
            {{ t('ui.add_filter')}}
          </template>
          <template #body>
            <div class="row">
              <div class="col-sm-12">
                <div class="form-group row">
                  <label class="col-form-label col-sm-3">{{t('ui.match')}}</label>
                  <div class="col-sm-9">
                    <VeeField v-slot="{ field, value, errorMessage, handleInput}" v-model="customFilter.model.condition" name="match" :label="t('ui.match')" :rules="{required:true}">
                      <SmartSelect
                        v-tooltip:top="errorMessage"
                        v-bind="field"
                        :model-value="value"
                        :class="{'is-invalid':errorMessage}"
                        :options="[['and_filters', t('ui.match_all_of')], ['or_filters', t('ui.match_one_of')]]"
                        id-index="0"
                        description-index="1"
                        @update:modelValue="handleInput($event);"/>
                    </VeeField>
                  </div>
                </div>
                <div class="form-group row">
                  <label class="col-form-label col-sm-3">{{t('ui.column')}}</label>
                  <div class="col-sm-9">
                    <VeeField v-slot="{ field, value, errorMessage, handleInput}" v-model="customFilter.model.column" name="column" :label="t('ui.column')" :rules="{required:true}">
                      <SmartSelect
                        v-tooltip:top="errorMessage"
                        v-bind="field"
                        :model-value="value"
                        :class="{'is-invalid':errorMessage}"
                        :options="filterColumn"
                        id-index="0"
                        description-index="1"
                        @update:modelValue="handleInput($event);"/>
                    </VeeField>
                  </div>
                </div>
                <div class="form-group row">
                  <label class="col-form-label col-sm-3">{{t('ui.criteria')}}</label>
                  <div class="col-sm-9">
                    <VeeField v-slot="{ field, value, errorMessage, handleInput}" v-model="customFilter.model.criteria" name="criteria" :label="t('ui.criteria')" :rules="{required:true}">
                      <SmartSelect
                        v-tooltip:top="errorMessage"
                        v-bind="field"
                        :model-value="value"
                        :class="{'is-invalid':errorMessage}"
                        :options="customFilter.criterias"
                        id-index="type"
                        description-index="desc"
                        @update:modelValue="handleInput($event);"/>
                    </VeeField>
                  </div>
                </div>
                <div class="form-group row">
                  <label class="col-form-label col-sm-3">{{t('ui.value')}}</label>
                  <div class="col-sm-9">
                    <VeeField v-slot="{ field, errorMessage}" v-model="customFilter.model.value" name="value" :label="t('ui.value')" :rules="{required:true}">
                      <input
                        v-tooltip:top="errorMessage"
                        type="text"
                        class="form-control form-control-sm"
                        v-bind="field"
                        :class="{'is-invalid':errorMessage}">
                    </VeeField>
                  </div>
                </div>
              </div>
            </div>
          </template>
          <template #footer class="form-actions">
            <button type="submit" class="btn btn-primary">{{t('ui.add')}}</button>
            <button type="button" class="btn btn-light" @click="hideAddCustomFilter">{{t('ui.cancel')}}</button>
          </template>
        </Modal>
      </form>
    </VeeForm>
    <table class="table table-hover">
      <thead v-if="hasHeaders">
        <tr>
          <th v-if="hasBulkDelete && hasDelete" class="actions checkbox">
            <span><input v-model="selectAll" class="form-check-input" type="checkbox"></span>
          </th>
          <th v-for="(column, index) in displayedColumns" :key="index" :style="columnsStyle[index] ? columnsStyle[index] : {}" :class="column.class">
            <slot :name="'th-'+index">
              <a class="table-order" @click="updateOrder(column)">
                <span>{{ column.label }}</span>
                <span v-show="react.currentOrder == column.name">
                  <i class="fa fa-sort-up text-muted float-end" />
                </span>
                <span v-show="react.currentOrder && react.currentOrder.charAt(0) === '-' && react.currentOrder.substring(1) == column.name">
                  <i class="fa fa-sort-down text-muted float-end" />
                </span>
              </a>
            </slot>
          </th>
          <th class="actions" />
        </tr>
      </thead>
      <tbody v-if="rows && rows.edges && rows.edges.length > 0">
        <tr v-for="(row, index) in rows.edges" :key="index" :class="rowClass(row)">
          <td v-if="hasDelete && hasBulkDelete" class="actions checkbox">
            <input v-model="selected" class="form-check-input" type="checkbox" :value="row.node">
          </td>
          <td v-for="(column, index) in displayedColumns" :key="index" :style="columnsStyle[index] ? columnsStyle[index] : {}" :class="column === 'timestamps' ? 'timestamp' : typeof column === 'object' && column.class ? column.class : ''">
            <slot :name="index" :node="row.node">
              <div v-if="fieldLinks[index] !== undefined">
                <router-link :to="fieldLinks[index](row.node, definition)" append v-html="printCell(index, row.node)" />
              </div>
              <div v-else-if="index === 'timestamps'" v-popover:left="getTimestampDetails(row)">
                {{ moment(row.node.create_date).fromNow() }}
              </div>
              <div v-else v-html="printCell(index, row.node)"/>
            </slot>
          </td>
          <td v-if="hasDelete || hasSlot('rowActions')" class="actions">
            <div class="dropdown">
              <button role="button" type="button" class="btn dropdown-toggle compact" data-bs-toggle="dropdown" aria-expanded="false">
                <i class="fas fa-ellipsis-v" />
              </button>
              <div class="dropdown-menu dropdown-menu-end">
                <slot name="rowActions" :node="row.node" />
                <hr v-if="hasDelete && hasSlot('rowActions')" class="dropdown-divider">
                <router-link v-if="hasDelete" class="dropdown-item" :to="getEditLink(row.node)" append>{{t('ui.edit')}}</router-link>
                <a v-if="hasDelete" href="#" class="dropdown-item text-danger" @click="rowsToDelete = [row.node]">{{t('ui.delete')}}</a>
              </div>
            </div>
          </td>
        </tr>
      </tbody>
      <tbody v-else-if="loading">
        <tr>
          <td colspan="99" align="center">
            &nbsp;<div class="dot-flashing" role="status" />&nbsp;
          </td>
        </tr>
      </tbody>
      <tbody v-else>
        <tr>
          <td colspan="99" align="center">
            {{ t("ui.no_item", {model:t(["models", definition.model, "name"].join(".")).toLowerCase()}) }}
          </td>
        </tr>
      </tbody>
    </table>

    <button v-if="rows && rows.pageInfo.hasNextPage" type="button" class="btn btn-sm btn-light me-2" :class="{disabled: loading}" @click="nextPage">
      {{ t("ui.more") }}
      <i class="fa fa-chevron-down" />
    </button>
    <button v-if="rows && rows.edges.length > limit" type="button" class="btn btn-sm btn-light me-2" :class="{disabled: loading}" @click="resetPage">
      {{ t("ui.less") }}
      <i class="fa fa-chevron-up" />
    </button>
    <span v-if="rows" class="text-muted">{{t('ui.records_of',{count: rows.edges.length, total_count: rows.total_count})}}</span>
  </div>
</template>

<script>

import Utils from './lib/utils.js'
import { useMutation, useQuery, useResult } from '@vue/apollo-composable'
import { ref, reactive, computed, inject, watch } from 'vue'
import { useRoute } from 'vue-router'
import { Form as VeeForm, Field as VeeField } from 'vee-validate'
import { useI18n } from 'vue-i18n'
import moment from 'moment'
import useStorage from '@/hooks/storage'


import Modal from '@/components/Modal'

import SmartSelect from '@/components/SmartSelect'

export default {
  props: {
    limit: {
      type: Number,
      default: 20
    },
    definition: {
      type: Object,
      required: true
    },
    columns: {
      type: Array,
      required: true
    },
    rowClass: {
      type: Function,
      default: function () {
        return null
      }
    },
    columnsStyle: {
      type: Object,
      default: function () {
        return {}
      }
    },
    additionalColumns: {
      type: Array,
      default: function () {
        return []
      }
    },
    requiredColumns: {
      type: Array,
      default: function () {
        return []
      }
    },
    hasDelete: {
      type: Boolean,
      default: true
    },
    hasBulkDelete: {
      type: Boolean,
      default: true
    },
    hasHeaders: {
      type: Boolean,
      default: true
    },
    hasControlsTop: {
      type: Boolean,
      default: true
    },
    links: {
      type: [Object, Boolean],
      default: function () {
        return {}
      }
    },
    filters: {
      type: Array,
      default: function () {
        return []
      }
    },
    deleteRefreshQueries: {
      type: Array,
      default: function () {
        return []
      }
    },
    views: {
      type: Array,
      default: function () {
        return [
          {
            description: 'All',
            filters: [],
            order: []
          }
        ]
      }
    },
    defaultOrder: {
      type: Array,
      default: function () {
        return []
      }
    },
    baseRoute: {
      type: String,
      default: ''
    }
  },
  setup: function(props, { emit, slots }) {
    const definitions = inject('definitions')
    const { t } = useI18n()
    const { quickSearches } = useStorage()
    const orderDebounce = Utils.createDebounce()
    const searchDebounce = Utils.createDebounce()

    const hasSlot = name => !!slots[name]

    const route = useRoute()

    const storageName = "sb-"+(route && route.name ? route.name : null)+"-"+props.definition.model

    const storage = {
      getStorage: function() {
        const defaultStorage = {
          additionalColumns: [],
          order: [],
          selectedView: props.views[0],
          quickSearch: '',
          managerFilter: [{ and_filters: [], or_filters: [] }]
        }

        let returnedStorage = defaultStorage

        try {
          returnedStorage = localStorage.getItem(storageName) ? JSON.parse(localStorage.getItem(storageName)) : defaultStorage
        } catch(error){
          returnedStorage = defaultStorage
        }

        return returnedStorage

      },
      saveStorage: function(data) {
        localStorage.setItem(storageName, data)
      },
    }

    const storageData = storage.getStorage()

    const buildQuickSearch = function(){

      const quickFilters = []

      const columns = dbColumns.value

      if(react.quickSearch != ''){
        for (let i = 0; i < columns.length; i++) {
          if (props.definition.fields[columns[i]]) {
            if (props.definition.fields[columns[i]].choices) {
              props.definition.fields[columns[i]].choices.forEach((item) => {
                if(item[1].toLowerCase().includes(react.quickSearch.toLowerCase())){
                  quickFilters.push({ field: columns[i], qs: item[0].replace('A_', '') })
                }
              })
            } else if (props.definition.fields[columns[i]].has_one){
              const relation = definitions[props.definition.fields[columns[i]].has_one.model]
              for(const columnName in relation.fields){
                const column = relation.fields[columnName]
                if (column.type == 'CharField') {
                  quickFilters.push({ field: columns[i]+'__'+columnName + '__icontains', qs: react.quickSearch })
                }
              }
            } else {
              quickFilters.push({ field: columns[i] + '__icontains', qs: react.quickSearch })
            }
          }
        }
      }
      return [{ or_filters: quickFilters }]
    }

    const quickSearch = function(){
      react.quickFilters = buildQuickSearch()
      quickSearches.value[storageName] = react.quickSearch
    }

    const react = reactive({
      currentOrder: storageData.currentOrder,
      order: storageData.order,
      selectedView: storageData.selectedView,
      quickFilters: [],
      quickSearch: quickSearches.value[storageName] ? quickSearches.value[storageName] : '',
      managerColumns : {},
      managerFilter: storageData.managerFilter
    })

    const getVerboseName = function (column) {

      const getName = function (definition, column) {
        let name = ''

        if (column === 'node_description') {
          name = t(['models', definition.model, 'name'].join('.'))
        } else if (column.includes('__')) {
          const columnParts = column.split('__')
          const field = columnParts.shift()
          if (!definition.fields[field]) {
            name = null
          }else if (definition.fields[field].has_one) {
            name = getName(definitions[definition.fields[field].has_one.model], columnParts.join('__'))
          }else if (definition.fields[field].belongs_to) {
            name = getName(definitions[definition.fields[field].belongs_to.model], columnParts.join('__'))
          }
        } else if (definition.fields[column]) {
          name = t(['models', definition.model, 'fields', column, 'name'].join('.'))
        }
        return name
      }
      const name = getName(props.definition, column.name ? column.name : column)

      return name
    }

    const getColumnDefinition = function(column) {
      const columnDefinition = typeof column == "object" ? column : {name: column}

      if(columnDefinition.label === undefined) {
        columnDefinition.label = (columnDefinition.name == 'timestamps' ? t('ui.created_on') : getVerboseName(column))
      }

      if(columnDefinition.columns === undefined) {
        if(columnDefinition.name == 'timestamps') {
          columnDefinition.columns = ['create_date','create_username', 'mod_date', 'mod_username']
        } else {
          columnDefinition.columns = [columnDefinition.name]
        }
      }

      if(!columnDefinition.order) {
        columnDefinition.order = columnDefinition.columns
      }

      return columnDefinition
    }

    props.columns.forEach(function(item) {
      react.managerColumns[item.name ? item.name : item] = getColumnDefinition(item)
      react.managerColumns[item.name ? item.name : item].displayed = true
      react.managerColumns[item.name ? item.name : item].additional = false
    })

    props.additionalColumns.forEach(function(item) {
      react.managerColumns[item.name ? item.name : item] = getColumnDefinition(item)
      react.managerColumns[item.name ? item.name : item].displayed = false
      react.managerColumns[item.name ? item.name : item].additional = true
    })

    storage.getStorage().additionalColumns.forEach(function(item) {
      if(react.managerColumns[item]){
        react.managerColumns[item].displayed = true
      }
    })

    const displayedColumns = computed(function() {
      return Object.fromEntries(Object.entries(react.managerColumns).filter(([_key, value]) => value.displayed === true))
    })

    const dbColumns = computed(function(){
      let columns = []
      const filteredColumns = displayedColumns.value

      for(const column in filteredColumns) {
        if(filteredColumns[column].displayed) {
          columns = [...columns, ...filteredColumns[column].columns]
        }
      }

      return [...new Set([...columns, ...props.requiredColumns])] // remove duplicates
    })

    react.quickFilters = buildQuickSearch()

    const { result, loading, fetchMore, refetch, onResult, variables } = useQuery(
      function() {
        return Utils.api.list(props.definition, dbColumns.value)
      },
      () => {
        return {
          order: [...react.order, ...react.selectedView.order, ...props.defaultOrder],
          filters: [...props.filters, ...react.quickFilters, ...react.selectedView.filters, ...react.managerFilter],
          limit: props.limit
        }
      }
    )

    const rows = useResult(result, null, (data) => {
      return data[props.definition.model + '_set']
    })

    onResult(() => {
      if(!loading.value){
        emit('on-results', rows.value)
      }
    })

    const { mutate: deleteRow } = useMutation(Utils.api.delete(props.definition), { refetchQueries : props.deleteRefreshQueries})

    const saveState = function(){
      const additionalColumns = []

      Object.keys(react.managerColumns).map(key => {
        if(react.managerColumns[key].displayed && react.managerColumns[key].additional){
          additionalColumns.push(key)
        }
      })

      const data = {
        additionalColumns: additionalColumns,
        currentOrder: react.currentOrder,
        order: react.order,
        selectedView: react.selectedView,
        managerFilter: react.managerFilter
      }

      storage.saveStorage(JSON.stringify(data))
    }

    const viewCount = ref([])
    const getViewCounts = ref(false)
    props.views.forEach(function(item, index){
      viewCount.value[index] = null

      const { result } = useQuery(
        function() {
          return Utils.api.count(props.definition)
        },
        () => {
          return {
            order: props.views[index].order,
            filters: [...props.filters, ...props.views[index].filters],
          }
        },
        () => ({
          enabled: getViewCounts.value,
        })
      )

      watch(result, value => {
        viewCount.value[index] = value[props.definition.model + '_set'].total_count
      })
    })

    const exportGraphqlFileName = ref(t(['models', props.definition.model, 'name'].join('.'), 2)+'.csv')
    const showExportGraphql = ref(false)

    const confirmExportGraphql = () => {
      showExportGraphql.value = true
    }

    const exportGraphql = async () => {

      await Utils.api.export(Utils.api.list(props.definition, dbColumns.value).loc.source.body, variables.value, exportGraphqlFileName.value, rows.value.total_count)
      showExportGraphql.value = false
    }

    const getEditLink = (row) => {
      const params = {}
      params[props.definition.model + '_id'] = row.id
      params[props.definition.model + '_description'] = row.node_description

      return {
        name: props.baseRoute+props.definition.model + '.edit',
        params: params
      }
    }

    return {t, moment, getEditLink, hasSlot, orderDebounce, searchDebounce, rows, loading, fetchMore, react, refetch, exportGraphql, deleteRow, dbColumns, storage, displayedColumns, saveState, quickSearch, viewCount, getViewCounts, showExportGraphql, exportGraphqlFileName, confirmExportGraphql}
  },
  data: function () {
    return {
      selected: [],
      rowsToDelete: false,
      deleteError: false,
      fieldLinks: {},
      after: null,
      showAddCustomFilter: false,
      customFilter: {
        model: {
          condition : 'and_filters',
          column : null,
          criteria: '__icontains',
          value: null
        },
        criterias : Utils.graphQlFilter()
      },
    }
  },
  computed: {
    selectAll: {
      get: function () {
        return this.rows ? this.selected.length === this.rows.length : false
      },
      set: function (value) {
        const selected = []

        if (value) {
          this.rows.edges.forEach(function (row) {
            selected.push(row.node)
          })
        }

        this.selected = selected
      }
    },
    filterColumn: function() {
      const data = []
      const definition = this.definition
      const t = this.t

      this.dbColumns.forEach(function(item) {
        data.push([item, t(['models', definition.model, 'fields', item, 'name'].join('.'))])
      })
      return data
    }
  },
  emits: ["on-results"],
  watch: {
    'react.quickSearch': {
      handler () {
        this.searchDebounce(() => {
          this.quickSearch()
        }, 500)
      }
    }
  },
  created: function () {
    const react = this.react
    this.fieldLinks = this.links ? this.links : {}

    const firstColumn = react.managerColumns[Object.keys(react.managerColumns)[0]]

    if (this.links !== false) {
      if (this.fieldLinks[firstColumn.name] === undefined) {
        const definition = this.definition
        const baseRoute = this.baseRoute
        const router = this.$router
        const getEditLink = this.getEditLink

        this.fieldLinks[firstColumn.name] = function (row) {
          const params = {}
          params[definition.model + '_id'] = row.id
          params[definition.model + '_description'] = row.node_description
          let route = {
            name: baseRoute+definition.model + '.view',
            params: params
          }
          try{
            router.resolve(route)
          }catch(err){
            route = getEditLink(row)
          }

          return route
        }
      }
    }

  },
  methods: {
    resetPage () {
      this.refetch()
    },
    nextPage () {
      this.after = this.rows.pageInfo.endCursor
      // Fetch more data and transform the original result
      this.fetchMore({
        variables: {
          after: this.after
        },
        // Transform the previous result with new data
        updateQuery: (previousResult, { fetchMoreResult }) => {
          if (previousResult[this.definition.model + '_set'].edges) {
            fetchMoreResult[this.definition.model + '_set'].edges = [...previousResult[this.definition.model + '_set'].edges, ...fetchMoreResult[this.definition.model + '_set'].edges]
          }
          return fetchMoreResult
        }
      })
    },
    getTimestampDetails: function (row) {
      return `<div class="text-nowrap">
                <div class="row">
                  <div class="col-sm-4"><b>${this.t('ui.created_on')}:</b></div>
                  <div class="col-sm-8">${this.moment(row.node.create_date).format('YYYY-MM-DD HH:mm:ss')}</div>
                </div>
                <div class="row">
                  <div class="col-sm-4"><b>${this.t('ui.created_by')}:</b></div>
                  <div class="col-sm-8">${row.node.create_username}</div>
                </div>
                <div class="row">
                  <div class="col-sm-4"><b>${this.t('ui.modified_on')}:</b></div>
                  <div class="col-sm-8">${this.moment(row.node.mod_date).format('YYYY-MM-DD HH:mm:ss')}</div>
                </div>
                <div class="row">
                  <div class="col-sm-4"><b>${this.t('ui.modified_by')}:</b></div>
                  <div class="col-sm-8">${row.node.mod_username}</div>
                </div>
              </div>`
    },
    printCell: function (column, row) {
      let result = null
      if (row[column] === undefined && column.includes('__')) {

        result = Utils.resolveDjangoPath(row, column, null)

        // todo dateformat
      } else if (row[column] !== undefined) {
        result = typeof row[column] === 'object' && row[column] !== null ? row[column].node_description : row[column]

        if (this.definition.fields[column] && this.definition.fields[column].choices) {
          result = this.t(['models', this.definition.model, 'fields', column, 'choices', result].join('.'))
        }

        if (this.definition.fields[column] && this.definition.fields[column].type === 'DateTimeField') {
          result = this.moment(row[column]).format('YYYY-MM-DD HH:mm:ss')
        }
      }

      return result
    },
    updateOrder: function (column) {

      let direction = ''
      const newOrderBy = []

      if (this.react.currentOrder === column.name) {
        direction = '-'
        this.react.currentOrder = direction+column.name
      } else {
        this.react.currentOrder = column.name
      }

      this.orderDebounce(() => {

        this.react.managerColumns[column.name].order.forEach(function(item) {
          newOrderBy.push(direction+item)
        })

        this.react.order = [...newOrderBy] // update order variable for apollo

        this.selected = []
        this.saveState()
      })
    },
    closeDelete: function () {
      this.rowsToDelete = false
      this.deleteError = false
    },
    confirmDelete: function () {
      this.deleteError = ''

      for (const idx in this.rowsToDelete) {
        this.deleteRow({id: this.rowsToDelete[idx].id}).then((data) => {
          const rowToDelete = this.rowsToDelete.shift()

          if (!data.data[this.definition.model + '_delete'].found) {
            this.deleteError += `Could not delete ${rowToDelete.node_description}. Maybe it was already deleted?\n`
          }
        }).catch((error) => {
          this.rowsToDelete.shift()
          this.deleteError += `${error}\n`
        })
      }

      this.refetch()
    },
    isAdditionalColumnSelected: function(column) {
      return this.storage.getStorage().additionalColumns.includes(column)
    },
    addAdditionalColumn: function(column) {
      //const obj_storage = this.storage.getStorage()

      if(this.react.managerColumns[column].displayed) {
        //obj_storage.additionalColumns.splice(obj_storage.additionalColumns.indexOf(column), 1)
        this.react.managerColumns[column].displayed = false
      } else {
        //obj_storage.additionalColumns.push(column)
        this.react.managerColumns[column].displayed = true
      }

      //obj_storage.additionalColumns = [ ...new Set(obj_storage.additionalColumns) ] // a set will remove duplicate
      //this.storage.saveStorage(JSON.stringify(obj_storage))
      this.saveState()
    },
    hideAddCustomFilter: function() {
      this.showAddCustomFilter = false
    },
    addCustomFilter: function() {
      this.showAddCustomFilter = true
    },
    removeCustomFilter: function (list, index) {
      list.splice(index, 1)
      this.saveState()
    },
    saveCustomFilter : function() {

      this.react.managerFilter[0][this.customFilter.model.condition].push({
        field: this.customFilter.model.column + this.customFilter.model.criteria, qs: this.customFilter.model.value
      })

      this.customFilter.model = {
        condition : 'and_filters',
        column : null,
        criteria: '__icontains',
        value: null
      }

      this.saveState()
      this.hideAddCustomFilter()
    },
    getCriteriaDesc: function(criteria){
      let desc = ''
      this.customFilter.criterias.forEach(function(item){
        if(item.type == criteria) {
          desc = item.desc
        }
      })
      return desc
    },
    placeHolder: function() {
      let placeholder = ''
      const keys = Object.keys(this.react.managerColumns)
      const max = keys.length > 4 ? 4 : keys.length

      for(let i = 0; i < max; i++) {
        placeholder += (this.react.managerColumns[keys[i]].label+'').toLowerCase() + ', '
      }

      return this.t('ui.search_by')+' '+placeholder.slice(0, -2)+'...'
    }
  },
  components: {VeeForm, VeeField, Modal, SmartSelect}
}
</script>
