<template>
  <div class="">
    <v-card class="elevation-0">
      <v-toolbar flat height="42" class="toolbar-border-bottom">
        <v-toolbar-title>
          <v-breadcrumbs
            :items="[{
                       text: nodes.env,
                       disabled: true,
                       href: '#'
                     },{
                       text: nodes.dbAlias,
                       disabled: true,
                       href: '#'
                     },
                     {
                       text: (nodes.tn || nodes.view_name) + ' (rows)',
                       disabled: true,
                       href: '#'
                     }]"
            divider=">"
            small
          >
            <template #divider>
              <v-icon small color="grey lighten-2">
                forward
              </v-icon>
            </template>
          </v-breadcrumbs>
        </v-toolbar-title>
        <v-spacer />
        <x-btn
          v-ge="['rows','reload']"
          outlined
          tooltip="Reload Rows"
          color="primary"
          small
          @click="refreshTable"
        >
          <v-icon small left>
            refresh
          </v-icon>
          Reload
        </x-btn>
        <x-btn
          v-if="!isView"
          v-ge="['rows','save']"
          outlined
          tooltip="Save Changes"
          color="primary"
          class="primary"
          small
          :disabled="disableSaveButton"
          @click.prevent="saveChanges"
        >
          <v-icon small left>
            save
          </v-icon>
          Save
        </x-btn>
        <x-btn
          v-if="!isView"
          v-ge="['rows','new']"
          outlined
          tooltip="Add New Row"
          color="primary"
          class="primary"
          small
          @click="addNewRow"
        >
          <v-icon small left>
            mdi-plus
          </v-icon>
          New Row
        </x-btn>
      </v-toolbar>

      <v-data-table
        :disable-sort="true"
        :server-items-length="totalCount"
        dense
        :headers="cols"
        :items="rows"
        hide-default-header
        :options.sync="tableOptions"
        class=" column-table"
        :footer-props="{
          itemsPerPageOptions:[5,10,25,50,100]
        }"
      >
        <template #header="{props:{headers}}">
          <th v-for="header in headers" :key="header.title" class="py-2 px-1 text-center text-capitalize">
            {{ header.text }}
          </th>
        </template>

        <template #item="{item,index}">
          <tr v-if="!item.isNewRow">
            <td v-for="({text,type,ai:ai},i) in cols" :key="i" class="caption">
              <span v-if="isView">
                {{ item.data[text] }}
              </span>
              <template v-else-if="text">
                <v-edit-dialog

                  v-ge="['rows','edit-save']"
                  :return-value.sync="item.data[text]"
                  @save="save(type,text,item)"
                >
                  {{ item.data[text] }}
                  <template #input>
                    <v-text-field
                      v-model="item.data[text]"
                      class="mt-0 caption"
                      label="Edit"
                      :type="getType(type)"
                      single-line
                      hide-details
                      dense
                      :disabled="ai"
                    />
                  </template>
                </v-edit-dialog>
              </template>
              <template v-else>
                <x-icon
                  v-ge="['rows','delete']"
                  small
                  color="error grey"
                  @click="deleteRow('showDialog', index, item)"
                >
                  mdi-delete-forever
                </x-icon>
              </template>
            </td>
          </tr>
          <tr v-else>
            <td v-for="({text,type,ai:ai},i) in cols" :key="i">
              <template v-if="text">
                <v-text-field
                  v-model="item.data[text]"
                  v-ge="['rows','save']"
                  dense
                  hide-details
                  label="Edit"
                  :type="getType(type)"
                  :placeholder="text"
                  :disabled="ai"
                  single-line
                  class="caption mt-n1 "
                  @input.passive="save(type,text,item)"
                />
              </template>
              <template v-else>
                <x-icon
                  v-ge="['rows','delete']"
                  small
                  color="error"
                  @click="deleteRow('showDialog',index ,item)"
                >
                  mdi-delete-forever
                </x-icon>
              </template>
            </td>
          </tr>
        </template>
      </v-data-table>
    </v-card>
    <dlgLabelSubmitCancel
      v-if="rowDeleteDlg"
      type="primary"
      :dialog-show="rowDeleteDlg"
      :actions-mtd="deleteRow"
      heading="Click Submit to Delete the Row"
    />
  </div>
</template>

<script>
import { mapGetters } from 'vuex'
import dlgLabelSubmitCancel from '../../utils/dlgLabelSubmitCancel.vue'
import findDataTypeMapping from '../../../helpers/findDataTypeMapping.js'

export default {
  components: {
    dlgLabelSubmitCancel
  },
  data() {
    return {
      rows: [],
      cols: [],
      dataTypes: [],
      rowDeleteDlg: false,
      selectedRowForDelete: null,
      client: null,
      primaryKeys: [],
      test: 'null',
      totalCount: 0,
      tableOptions: {},
      disableSaveButton: true
    }
  },
  methods: {
    async handleKeyDown({ metaKey, key, altKey, shiftKey, ctrlKey }) {
      console.log(metaKey, key, altKey, shiftKey, ctrlKey)
      // cmd + s -> save
      // cmd + l -> reload
      // cmd + n -> new
      // cmd + d -> delete
      // cmd + enter -> send api

      switch ([metaKey, key].join('_')) {
        case 'true_s' :
          await this.saveChanges()
          break
        case 'true_l' :
          await this.refreshTable()
          break
        case 'true_n' :
          this.addNewRow()
          break
        // case 'true_d' :
        //   await this.deleteTable('showDialog');
        //   break;
      }
    },

    async refreshTable() {
      try {
        await this.loadColumnList()
        await this.loadRowList()
      } catch (e) {
        this.$toast.error('error loading rows').goAway(4000)
        throw e
      }
    },
    async loadColumnList() {
      // const columnsList = await this.client.columnList({tn: this.nodes.tn});

      // const columnsList = await this.sqlMgr.sqlOp({
      //   env: this.nodes.env,
      //   dbAlias: this.nodes.dbAlias
      // }, 'columnList', {tn: this.nodes.tn})

      const columnsList = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
        env: this.nodes.env,
        dbAlias: this.nodes.dbAlias
      }, 'columnList', { tn: this.nodes.tn || this.nodes.view_name }])

      this.cols = columnsList.data.list.map(({ cn, dt, ai, pk }) => {
        if (pk) { this.primaryKeys.push(cn) }
        return {
          text: cn, value: cn, type: findDataTypeMapping(dt), ai
        }
      })
      // column for action buttons
      if (!this.isView) { this.cols.push({ text: '', value: '' }) }
    },
    async loadRowList() {
      const { page, itemsPerPage } = this.tableOptions

      // const result = await this.sqlMgr.sqlOp({
      //   env: this.nodes.env,
      //   dbAlias: this.nodes.dbAlias
      // }, 'list', {
      //   tn: this.nodes.tn,
      //   size: itemsPerPage,
      //   page,
      //   orderBy: this.primaryKeys.map(key => ({column: key, order: 'desc'}))
      // })

      const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
        env: this.nodes.env,
        dbAlias: this.nodes.dbAlias
      }, 'list', {
        tn: this.nodes.tn || this.nodes.view_name,
        size: itemsPerPage,
        page,
        orderBy: this.primaryKeys.map(key => ({ column: key, order: 'desc' }))
      }])

      // const result = await this.client.list({
      //   tn: this.nodes.tn,
      //   size: itemsPerPage,
      //   page,
      //   orderBy: this.primaryKeys.map(key => ({column: key, order: 'desc'}))
      // });

      this.totalCount = result.data.count

      this.rows = result.data.list.map((row) => {
        const keys = this.primaryKeys.reduce((obj, key) => Object.assign(obj, { [key]: row[key] }), {})
        return { keys, data: { ...row }, dataCopy: { ...row } }
      })
    },
    save(type, text, item) {
      // console.log(type, text, item)
      item.changed = true
      const { data, dataCopy } = item
      if (type === 'date') {
        dataCopy[text] = new Date(data[text])
      } else {
        dataCopy[text] = data[text]
      }
    },
    getType(dt) {
      if (dt === 'number') { return 'number' }
      return 'text'
    },
    async deleteRow(action = '', index, row) {
      try {
        if (action === 'showDialog') {
          this.rowDeleteDlg = true
          this.selectedRowForDelete = { index, row }
        } else if (action === 'hideDialog') {
          this.rowDeleteDlg = false
        } else {
          this.rowDeleteDlg = false
          const { index, row } = this.selectedRowForDelete
          if (row.isNewRow) {
            this.rows.splice(index, 1)
          } else {
            // this.client.delete(this.nodes.tn, row.keys)

            await this.$store.dispatch('sqlMgr/ActSqlOp', [{
              env: this.nodes.env,
              dbAlias: this.nodes.dbAlias
            }, 'delete', {
              tn: this.nodes.tn || this.nodes.view_name,
              whereConditions: row.keys
            }])

            // await this.sqlMgr.sqlOp({
            //   env: this.nodes.env,
            //   dbAlias: this.nodes.dbAlias
            // }, 'delete', {
            //   tn: this.nodes.tn,
            //   whereConditions: row.keys
            // });

            this.rows.splice(index, 1)
          }
          this.$toast.success('Row deleted successfully').goAway(3000)
        }
        this.totalCount--
      } catch (e) {
        this.$toast.error('Deleting row failed').goAway(3000)
        throw e
      }
    },
    addNewRow() {
      this.rows.unshift({ isNewRow: true, data: {}, dataCopy: {} })
      this.totalCount++
    },
    async saveChanges() {
      try {
        const newRows = []
        this.rows.map(async(item) => {
          const { keys, isNewRow, changed, dataCopy } = item
          if (isNewRow) {
            newRows.push(dataCopy)
          } else if (changed) {
            item.changed = false
            // const res = await this.client.update(this.nodes.tn, dataCopy, keys);

            const res = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
              env: this.nodes.env,
              dbAlias: this.nodes.dbAlias
            }, 'update', {
              tn: this.nodes.tn,
              data: dataCopy,
              whereConditions: keys
            }])

            console.log(res)
            this.$toast.success('Row updated successfully').goAway(3000)
          }
        })
        if (newRows.length) {
          console.log(newRows)
          // todo : multiargs to single object
          // const res = await this.client.insert(this.nodes.tn, newRows)

          const res = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
            env: this.nodes.env,
            dbAlias: this.nodes.dbAlias
          }, 'insert', {
            tn: this.nodes.tn,
            data: newRows
          }])

          console.log(res)
        }
        this.$toast.success('Row saved successfully').goAway(3000)
        this.loadRowList()
      } catch (e) {
        console.log(e)
        this.$toast.error('Saving changes to table failed').goAway(3000)
        throw e
      }
    }
  },
  computed: {
    ...mapGetters({ sqlMgr: 'sqlMgr/sqlMgr' }),
    isView() {
      return !!this.nodes.view_name
    }
  },
  beforeCreated() {
  },
  watch: {
    tableOptions: {
      handler() {
        this.loadRowList()
      },
      deep: true
    },
    rows: {
      handler() {
        this.disableSaveButton = !this.rows.some(row => row.isNewRow || row.changed)
      },
      deep: true
    }
  },
  async created() {
    await this.refreshTable()
  },
  mounted() {
  },
  beforeDestroy() {
  },
  destroy() {
  },
  directives: {},
  validate({ params }) {
    return true
  },
  head() {
    return {}
  },
  props: ['nodes', 'newTable', 'mtdNewTableUpdate', 'deleteTable']
}
</script>

<style scoped>
</style>
<!--
/**
 * @copyright Copyright (c) 2021, Xgene Cloud Ltd
 *
 * @author Naveen MR <oof1lab@gmail.com>
 * @author Pranav C Balan <pranavxc@gmail.com>
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */
-->