<script lang="ts">
import { ref } from 'vue'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import { faRefresh, faSearch, faIndent, faCheck } from '@fortawesome/free-solid-svg-icons'; 
import { faSquare } from '@fortawesome/free-regular-svg-icons';
import { HeaderModel, Options } from '@/components/models/tablemodels';
import { PaginatonModel } from '@/components/models/tablemodels';
import { change, itemSelection, load, multiSelection, rowClass, rowClick, search, selectedRow, unSelectedRow } from '@/components/helpers/resources';
import Date from '@/components/headerFilters/Date.vue';
import Search from '@/components/search/SearchView.vue';
import Text from '@/components/headerFilters/Text.vue';
import Number from '@/components/headerFilters/Number.vue';
import Filters from '@/components/headerFilters/Filters.vue';
import SortView from '@/components/sort/SortView.vue';
import PaginationView from '@/components/pagination/PaginationView.vue';
import DataItem from '@/components/table/data/ItemView.vue';
import { isEqual } from '../helpers/instances';
import { DataSetHeader } from '../dataSets/dataSetHeader';
import { changeActiveSets, changeMultipleSets, changeSet, DataSetItems } from '../dataSets/dataSetItems';

export default {
  props: {
    dataheader: {
      type: Array<HeaderModel>,
      default: () => []
    },
    options: {
      type: Options,
      required: false,
      default: () => new Options()
    },
    name: {
      type: String
    },
    dataItems: {
      type: Array<Object>,
      reactive: true,
      required: true,
      default: () => []
    },
    currentItem: {
      type: Object,
      required: false
    },
    currentId: {
      type: Number,
      required: false
    },
    loading: {
      type: Boolean,
      required: false,
      default: false
    },
    crud: {
      type: Boolean,
      required: false,
      default: false
    },
    showFilters: {
      type: Boolean,
      required: false,
      default: () => false
    },
    dialogWidth: {
      type: Number,
      default: () => 800
    },
    itemsPerPage: {
      type: Number,
      default: () => 10
    },
    pagination: {
      type: PaginatonModel,
      required: false,
      default: () => new PaginatonModel()
    },
    showTime: {
      type: Boolean,
      required: false,
      default: () => false
    },
    select: {
      type: Boolean,
      required: false,
      default: () => false,
    },
    multiSelect: {
      type: Boolean,
      required: false,
      default: () => false,
    },
    selectedItems: {
      type: Array<Object>,
      required: false,
      default: () => []
    }
  },
  components: {
    FontAwesomeIcon: FontAwesomeIcon,
    Date: Date,
    Text: Text,
    Number: Number,
    SortView: SortView,
    PaginationView: PaginationView,
    Filters: Filters,
    DataItem: DataItem,
    Search: Search
  },
  mounted() {
    this.firstChange = true;
    this.load({});
  },
  watch: {
    dataItems(newValue, oldValue) {
      this.initData(newValue);
      if(this.firstChange){
        this.initFilters();
        this.firstChange = false;
        setTimeout(() => {
          this.loaded = true;
        }, 800)
      }
    },
    options(newValue, oldValue){
      console.log(newValue);
      this.options = newValue;
    },
    dataSetItems(newValue, oldValue){
      this.dataSetItems = newValue;
    },
    pagination(newValue: PaginatonModel, oldValue) {
      this.page = newValue.CurrentPage;
      this.perPage = newValue.PerPage;
      this.pageCount = newValue.PageCount;
      this.totalCount = newValue.TotalCount;
    }
  },
  emits: [change, load, rowClick, search, itemSelection, multiSelection],
  data() {
    return {
      rowClass: rowClass,
      dataheader: this.dataheader,
      dataItems: this.dataItems,
      dialog: false,
      selected: this.selectedItems,
      new: true,
      dataSetItems: [] as DataSetItems[],
      dataSetHeaders: [] as DataSetHeader[],
      loaded: false,
      options: this.options,
      name: this.name,
      currentId: this.currentId,
      currentItem: this.currentItem,
      loading: this.loading,
      faSearch: faSearch,
      reload: faRefresh,
      faIndent: faIndent,
      faCheck: faCheck,
      faSquare: faSquare,
      multiSelectedItems: [] as Object[],
      lastItem: {},
      completes: this.completes,
      filters: { CurrentPage: 1, PerPage: 10, SortColumn: '', SortDirection: 1 } as any,
      showFilters: this.showFilters,
      modelValue: ref([]),
      firstChange: true,
      multiSelected: false,
      perPage: this.pagination!.PerPage,
      page: this.pagination!.CurrentPage,
      pageCount: this.pagination!.PageCount,
      totalCount:this.pagination!.TotalCount,
      showTime: this.showTime,
      isEqual: isEqual,
      changeMultipleSets: changeMultipleSets,
      changeActiveSets: changeActiveSets,
      changeSet: changeSet
    };
  },
  methods: {
    rowClick(event: {}){
      this.$emit(rowClick, event);
    },
    load(event: {}){
      if(this.onLoad) this.onLoad(event);
    },
    refresh(){
      this.clear();
      this.search();
    },
    clear(){
      for(let prop of Object.keys(this.filters)){
        this.filters[prop] = null;
      }
    },
    initData(dataItems){
      let dataSetItems = [] as DataSetItems[];

      for(let [index, item] of dataItems.entries()){
        let dataSet = new DataSetItems();
        dataSet.id = index + 1;
        dataSet.dataItem = item;

        dataSet.changeMultipleSet = [(item: DataSetItems) => {
          if(this.multiSelectedItems.some(element => isEqual(element, item.dataItem))){
            item.properties.rowClass = unSelectedRow;
            item.properties.selected = false;
          }else{
            item.properties.rowClass = selectedRow;
            item.properties.selected = true;
          }
        }];

        dataSet.changeItemSet = [(item: DataSetItems, dataItems: DataSetItems[]) => {
          for(let dataSet of dataItems){
            dataSet.properties.rowClass = unSelectedRow;
          }

          changeActiveSets(dataSet.changeMultipleSet, item);
        }]
        
        if(dataSet.id == 1){
          dataSet.startPosition = true;
        }

        dataSetItems = [...dataSetItems, dataSet];
      }

      this.dataSetItems = dataSetItems;
      this.dataItems = dataItems;

    },
    initHeaders() {
      let dataSetHeaders = [] as DataSetHeader[];

      for(let [index, item] of this.dataheader.entries()){
        let dataHeader = new DataSetHeader();
        dataHeader.id = index + 1;
        dataHeader.dataHeader = item;
        
        if(dataHeader.id == 1) {
          dataHeader.startPosition = true;
        }

        dataSetHeaders = [...dataSetHeaders, dataHeader];
      }

      this.dataSetHeaders = dataSetHeaders;
    },
    initFilters() {
      let item = this.dataItems[0];
      for(let key of Object.keys(item)){
        this.filters[key] = null;
      }
      this.filters.CurrentPage = 0;
      this.filters.PerPage = 0;
    },
    search(){
      if(this.filters != undefined){
        this.$emit(search, this.filters);
      }
    },
    async updateItem(item: DataSetItems, index: number){
      if(!this.crud){
        this.rowClick(item.dataItem);
      }else{
        this.currentId = item.dataItem[this.options.Key!];
        this.$emit(change, item.dataItem);
      }
      
      if(this.select){
        for(let dataSet of this.dataSetItems){
          dataSet.properties.rowClass = unSelectedRow;
        }

        changeMultipleSets(item.changeItemSet, item, this.dataSetItems);
        this.$emit(itemSelection, item.dataItem);
      }

      if(this.multiSelect){
        
        if(!this.multiSelectedItems.length){
          this.multiSelectedItems = [item.dataItem];
        }else if(this.multiSelectedItems.some(element => isEqual(element, item.dataItem))){
          this.multiSelectedItems = this.multiSelectedItems.filter(element => !isEqual(element, item.dataItem));
        }else{
          this.multiSelectedItems = [...this.multiSelectedItems, item.dataItem]
        }

        changeActiveSets(item.changeMultipleSet, item);
        this.$emit(multiSelection, this.multiSelectedItems);
      }
    },
    filterValue(event: any, dataItem: any){
      let item = dataItem;
      let value = event.target.value;
      if(item != null){
        dataItem = value == '' ? null : value;
      }else{
        dataItem = value;
      }
    },
    filterDate(event: any, dataItem: any){
      let item = dataItem;
      if(item != null){
        dataItem = event == '' ? null : new window.Date(event);
      }else{
        dataItem = new window.Date(event);
      }
    },
    optionschange(event: any){
      this.page = event!.page;
      this.filters.CurrentPage = this.page;
      this.search();
    },
    nextPage(event: any){
      if(this.page < this.pageCount){
        this.page = this.page + 1;
        this.filters.CurrentPage = this.page;
        this.search();
      }
    },
    previousPage(event: any){
      if(this.page > 1){
        this.page = this.page - 1;
        this.filters.CurrentPage = this.page;
        this.search();
      }
    },
    firstPage(event: any){
      this.page = 1;
      this.filters.CurrentPage = this.page;
      this.search();
    },
    lastPage(event: any){
      this.page = this.pageCount;
      this.filters.CurrentPage = this.page;
      this.search();
    },
    pageChange(event: any){
      this.page = event;
      this.filters.CurrentPage = this.page;
      this.search();
    },
    pageSize(event: any){
      console.log(event);
      this.perPage = event;
      this.filters.PerPage = this.perPage;
      this.search();
    },
    sort(event: any, prop: any, index: number){
      prop.sort = !prop.sort;
      this.filters.SortColumn = Object.keys(this.dataItems[0])[index];
      this.filters.SortDirection = window.Number(prop.sort);
      this.search();
    },
    selectItem(event){
      console.log(event);
    },
    multiSelectItems(event){
      changeSet(this.dataSetItems, this.multiSelected);
      this.multiSelected = !this.multiSelected;
    }
  }
}
</script>

<template>
  <div>
    <v-container>
      <v-row style="border-bottom: 1px solid #393E46; padding: 10px">
        <v-btn @click="search()" style="margin-right: 10px" color="#1697f6" v-if="showFilters" v-tooltip="'Search'">
          <FontAwesomeIcon :icon="faSearch"></FontAwesomeIcon>
        </v-btn>
        <v-btn @click="refresh()" style="margin-right: 10px" color="#1697f6" v-if="showFilters" v-tooltip="'Refresh'">
          <FontAwesomeIcon :icon="reload"></FontAwesomeIcon>
        </v-btn>
      </v-row>
      <v-row>
        <v-data-table 
          v-if="loaded"
          @update:options="optionschange($event)"
          :v-bind:loading-text="'Loading... Please wait'"
          :color="'white'"
          :striped="'odd'"
          :loading="loading"
          :v-bind:model-value="modelValue"
          :items="dataItems"
          :items-per-page="perPage"
          :page="page"
          hide-default-header
          hide-default-footer
          multi-sort
          hover
          return-object> 
          <template v-slot:item="{ item, index }">
            <template v-for="dataSet in dataSetItems" :v-bind="item" v-bind:key="dataSet.id">
              <template v-if="isEqual(item, dataSet.dataItem)">
                <tr v-if="dataSet.startPosition && showFilters" class="filter-items" >
                  <td v-if="multiSelect" @click="multiSelectItems($event)">
                    <FontAwesomeIcon v-if="multiSelected" :icon="faCheck"></FontAwesomeIcon>
                    <FontAwesomeIcon v-else :icon="faSquare"></FontAwesomeIcon>
                  </td>
                  <td v-for="(item, index) in dataheader">
                    <SortView 
                      :options="options"
                      :dataHeader="item" 
                      :startPosition="index < 1"
                      :id="index" 
                      @sort="sort($event, item, index)">
                    </SortView>
                  </td>
                </tr>
                <tr v-if="dataSet.startPosition && showFilters" class="filter-items" >
                  <td v-if="multiSelect">
                  </td>
                  <td v-for="prop in Object.keys(dataSet.dataItem)">
                    <Filters 
                      :item="dataSet.dataItem" 
                      :filters="filters" 
                      :showFilters="showFilters" 
                      :options="options"
                      :prop="prop"
                      @filterValue="filterValue($event, filters[prop])">
                    </Filters>
                  </td>
                </tr>
                <tr @click="updateItem(dataSet, dataSet.id!)" v-bind="dataSet.properties" :class="dataSet.properties.rowClass">
                  <td v-if="multiSelect">
                    <FontAwesomeIcon v-if="dataSet.properties.selected" :icon="faCheck"></FontAwesomeIcon>
                    <FontAwesomeIcon v-else :icon="faSquare"></FontAwesomeIcon>
                  </td>
                  <td v-for="(prop) in Object.keys(dataSet.dataItem)">
                    <DataItem 
                      :item="dataSet.dataItem" 
                      :prop="prop" 
                      :options="options"
                      :id="dataSet.id!">
                    </DataItem>
                  </td>
                </tr>
              </template>
            </template>
          </template>
        </v-data-table>
        <v-data-table-server 
          v-else
          :items-length="0"
          item-key="name"
          loading-text="Loading... Please wait"
          loading>
        </v-data-table-server>
      </v-row>
      <PaginationView 
        v-if="loaded"
        :page="page" 
        :perPage="perPage" 
        :pageCount="pageCount" 
        :totalCount="totalCount" 
        @pageChange="pageChange($event)" 
        @pageSize="pageSize($event)" 
        @firstPage="firstPage($event)" 
        @previousPage="previousPage($event)" 
        @nextPage="nextPage($event)" 
        @lastPage="lastPage($event)"/>
    </v-container>
  </div>
</template>

<style>
@media (min-width: 1024px) {
  .about {
    min-height: 100vh;
    display: flex;
    align-items: center;
  }
}

.filter-items{
  height: 56px;
}

.filter-items .v-input__control{
  height: 56px;
}

.filter-items span{
  height: 56px;
}

.filter-items span div{
  height: 56px;
}

.filter-items span div div{
  height: 56px;
}

.selected-row{
  background-color: rgb(209, 208, 208);
}

</style>
