<template>
  <div class="h-100">
    <v-card style="" class="h-100">
      <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.title || nodes.view_name || nodes.table_name) + ' (RBAC)',
                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="['acl', 'reload']" outlined tooltip="Reload RBAC" color="primary" small @click="load">
          <v-icon small left> refresh </v-icon>
          <!-- Reload -->
          {{ $t('general.reload') }}
        </x-btn>

        <x-btn
          v-ge="['acl', 'save']"
          outlined
          :tooltip="$t('tooltip.saveChanges')"
          color="primary"
          class="primary"
          small
          :disabled="!edited"
          @click="save"
        >
          <v-icon small left> save </v-icon>
          <!-- Save -->
          {{ $t('general.save') }}
        </x-btn>
      </v-toolbar>

      <p class="title mt-6 mb-6">
        Table : <span class="text-capitalize">{{ nodes.title || nodes.view_name }}</span
        ><br />
        <span class="font-weight-thin">Role Based Access Control (RBAC) For Columns</span>
      </p>

      <v-skeleton-loader v-if="loading || !data" type="table" />

      <div v-else class="pb-10">
        <v-overlay v-model="showCustomAcl" absolute>
          <template #default>
            <v-card
              :light="!$store.state.settings.darkTheme"
              class="ma-2"
              style="max-height: 100%; overflow: auto; min-height: 70vh"
            >
              <v-card-actions>
                <p class="body-1 mb-0 mr-2">
                  Custom Rules : {{ custoAclTitle[0] }}<span class="grey--text caption">(table)</span> >
                  {{ custoAclTitle[1] }}<span class="grey--text caption">(role)</span> > {{ custoAclTitle[2]
                  }}<span class="grey--text caption">(operation)</span>
                </p>
                <v-spacer />
                <v-btn outlined small @click="showCustomAcl = false">
                  <!-- Cancel -->
                  {{ $t('general.cancel') }}
                </v-btn>
                <v-btn outlined color="primary" small @click="save">
                  <!-- Save -->
                  {{ $t('general.save') }}
                </v-btn>
              </v-card-actions>
              <v-card-text>
                <custom-acl v-model="customAcl" :nodes="nodes" :table="nodes.table_name || nodes.view_name" />
              </v-card-text>
            </v-card>
          </template>
        </v-overlay>
        <v-simple-table dense class="mx-10">
          <thead>
            <tr>
              <th rowspan="2" class="text-center">
                <!--            <div class="d-flex justify-center align-end">-->
                <!--              <v-checkbox dense v-model="aclAll"></v-checkbox>-->

                <span>Columns x RBAC</span>
                <!--          <v-text-field dense hide-details class="my-2 caption font-weight-regular"
                                                            flat
                                                            outlined
                                                            :placeholder="`Search columns in '${nodes.title|| nodes.view_name}'`"
                                                            prepend-inner-icon="search" v-model="search"
          ></v-text-field>-->
                <!--            </div>-->
              </th>
              <template v-for="role in roles">
                <th v-if="role !== 'creator'" :key="role" :colspan="operations.length" class="text-center">
                  {{ role }}
                </th>
              </template>
            </tr>
            <tr>
              <template v-for="role in roles">
                <template v-if="role !== 'creator'">
                  <th
                    v-for="op in operations"
                    :key="`${role}-${op.name}--11`"
                    :class="` pa-0 caption text-capitalize ${op.color}--text`"
                    class="permission role-op-header"
                  >
                    <v-tooltip bottom>
                      <template #activator="{ on }">
                        <div class="d-flex flex-column justify-center align-center d-100 h-100 mt-0" v-on="on">
                          <v-checkbox
                            v-model="aclRoleOpAll[`${role}___${op.name}`]"
                            hide-details
                            class="mt-n1"
                            dense
                            :color="op.color"
                            @change="onAclRoleOpAllChange(aclRoleOpAll[`${role}___${op.name}`], `${role}___${op.name}`)"
                          />
                          <span>{{ op.name }}</span>
                        </div>
                      </template>
                      <span class="caption"
                        ><span class="text-capitalize">{{ role }}</span>
                        {{ aclRoleOpAll[`${role}___${op.name}`] ? 'can' : "can't" }} {{ op.name }} '{{
                          nodes.table_name
                        }}' rows</span
                      >
                    </v-tooltip>

                    <v-icon
                      v-if="op.name !== 'delete'"
                      x-small
                      class="custom-acl"
                      @click="
                        (showCustomAcl = true),
                          (custoAclTitle = [nodes.table_name, role, op.name]),
                          (customAcl = (data[role] && data[role][op.name] && data[role][op.name].custom) || {})
                      "
                    >
                      mdi-pencil-outline
                    </v-icon>

                    <v-icon
                      v-if="
                        data[role] &&
                        data[role][op.name] &&
                        data[role][op.name].custom &&
                        Object.keys(data[role][op.name].custom).length
                      "
                      x-small
                      class="custom-acl-found"
                    >
                      mdi-filter-menu
                    </v-icon>
                  </th>
                </template>
              </template>
            </tr>
          </thead>
          <tbody>
            <tr
              v-for="column in columns"
              v-show="column.title.toLowerCase().indexOf(search.toLowerCase()) > -1"
              :key="column.title"
              class="caption"
            >
              <td>
                {{ column.title }}
              </td>
              <template v-for="role in roles">
                <template v-if="role !== 'creator'">
                  <td
                    v-for="op in operations"
                    :key="`${role}-${op.name}`"
                    class="pa-0"
                    style="position: relative"
                    :class="`caption text-capitalize`"
                  >
                    <v-tooltip bottom :disabled="op.ignore">
                      <template #activator="{ on }">
                        <div
                          class="d-100 h-100 d-flex align-center justify-center permission-checkbox-container"
                          v-on="on"
                        >
                          <v-checkbox
                            v-if="!op.ignore"
                            v-model="aclObj[`${column.title}___${role}___${op.name}`]"
                            class="mt-n1"
                            dense
                            color="primary lighten-2"
                            style=""
                            @change="
                              onPermissionChange(
                                aclObj[`${column.title}___${role}___${op.name}`],
                                `${role}___${op.name}`
                              )
                            "
                          />

                          <v-checkbox v-else class="mt-n1" dense color="primary lighten-2" disabled style="" />
                        </div>
                      </template>

                      <span class="caption"
                        ><span class="text-capitalize">{{ role }}</span>
                        {{ aclObj[`${column.title}___${role}___${op.name}`] ? 'can' : "can't" }} {{ op.name }} column
                        '{{ column.title }}'</span
                      >
                    </v-tooltip>
                  </td>
                </template>
              </template>
            </tr>
          </tbody>
        </v-simple-table>
      </div>
    </v-card>
  </div>
</template>

<script>
// import debounce from "@/helpers/debounce";
// import CustomAcl from "./customAcl";

import CustomAcl from './CustomAcl';

export default {
  name: 'TableAcl',
  components: { CustomAcl },
  // components: {CustomAcl},
  props: ['nodes'],
  data: () => ({
    showCustomAcl: false,
    custoAclTitle: null,
    customAcl: {},
    edited: false,
    search: '',
    allOperations: [
      {
        name: 'create',
        color: 'warning',
      },
      {
        name: 'read',
        color: 'success',
      },
      {
        name: 'update',
        color: 'info',
      },
      {
        name: 'delete',
        color: 'error',
        ignore: true,
      },
    ],

    data: null,
    columns: null,
    aclObj: {},
    aclRoleOpAll: {},
    loading: false,
  }),
  computed: {
    roles() {
      return (this.data ? Object.keys(this.data) : []).filter(r => r !== 'guest');
    },
    operations() {
      return this.allOperations.filter(({ name }) => this.nodes.table_name || name === 'read');
    },
  },
  async created() {
    await this.load();
  },
  methods: {
    async load() {
      await this.loadColumnList();
      await this.loadAcl();
      this.generateAclObj();
      this.edited = false;
    },
    generateAclObj() {
      const aclObj = {};
      const aclRoleOpAll = {};
      console.log(this.data);
      // generate aclObj with merged key value
      for (const [role, roleObj] of Object.entries(this.data)) {
        for (const [operation, acl] of Object.entries(roleObj)) {
          aclRoleOpAll[`${role}___${operation}`] = false;
          for (const { _cn: cn } of this.columns) {
            if (typeof acl === 'boolean') {
              aclObj[`${cn}___${role}___${operation}`] = acl;
            } else if (acl) {
              aclObj[`${cn}___${role}___${operation}`] = acl.columns[cn];
            }
            if (!aclRoleOpAll[`${role}___${operation}`] && aclObj[`${cn}___${role}___${operation}`]) {
              aclRoleOpAll[`${role}___${operation}`] = true;
            }
          }
        }
      }
      this.aclRoleOpAll = aclRoleOpAll;
      this.$nextTick(() => {
        this.aclObj = aclObj;
      });
    },
    async save() {
      const obj = {};
      for (const [key, isAllowed] of Object.entries(this.aclObj)) {
        const [column, role, operation] = key.split('___');
        if (operation !== 'delete') {
          obj[role] = obj[role] || {};
          obj[role][operation] = obj[role][operation] || {};
          obj[role][operation].columns = obj[role][operation].columns || {};
          obj[role][operation].columns[column] = isAllowed;
        }
        if (this.data[role] && this.data[role][operation] && this.data[role][operation].custom) {
          obj[role][operation].custom = this.data[role][operation].custom;
        }
      }

      for (const [key, isAllowed] of Object.entries(this.aclRoleOpAll)) {
        const [role, operation] = key.split('___');
        if (operation === 'delete' || !isAllowed) {
          obj[role] = obj[role] || {};
          obj[role][operation] = isAllowed;
        }
      }

      if (this.showCustomAcl && this.custoAclTitle) {
        if (
          !obj[this.custoAclTitle[1]][this.custoAclTitle[2]] ||
          typeof obj[this.custoAclTitle[1]][this.custoAclTitle[2]] !== 'object'
        ) {
          obj[this.custoAclTitle[1]][this.custoAclTitle[2]] = {};
        }
        obj[this.custoAclTitle[1]][this.custoAclTitle[2]].custom = this.customAcl;
      }

      console.log(obj);
      try {
        await this.$store.dispatch('sqlMgr/ActSqlOp', [
          {
            env: this.nodes.env,
            dbAlias: this.nodes.dbAlias,
          },
          'xcAclSave',
          {
            tn: this.nodes.table_name || this.nodes.view_name,
            acl: obj,
          },
        ]);
        if (this.showCustomAcl) {
          this.$toast.success('Custom RBAC saved successfully').goAway(3000);
          this.showCustomAcl = false;
        } else {
          this.$toast.success('RBAC saved successfully').goAway(3000);
        }
        this.edited = false;
        await this.load();
      } catch (e) {
        this.$toast.error(e.message).goAway(3000);
      }
    },

    async loadColumnList() {
      // const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [{
      //   env: this.nodes.env,
      //   dbAlias: this.nodes.dbAlias
      // }, 'columnList', {
      //   tn: this.nodes.table_name || this.nodes.view_name
      // }]);
      // this.columns = result.data.list;
      const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [
        {
          env: this.nodes.env,
          dbAlias: this.nodes.dbAlias,
        },
        'tableXcModelGet',
        {
          tn: this.nodes.table_name || this.nodes.view_name,
        },
      ]);

      const meta = JSON.parse(result.meta);
      this.columns = meta.columns;
    },
    async loadAcl() {
      this.loading = true;
      const result = await this.$store.dispatch('sqlMgr/ActSqlOp', [
        {
          env: this.nodes.env,
          dbAlias: this.nodes.dbAlias,
        },
        'xcAclGet',
        {
          tn: this.nodes.table_name || this.nodes.view_name,
        },
      ]);
      this.data = JSON.parse(result.acl);

      this.loading = false;
    },
    onAclRoleOpAllChange(isEnabled, name) {
      this.edited = true;
      const obj = {};
      for (const key in this.aclObj) {
        if (key.split('___').slice(1).join('___') === name) {
          obj[key] = isEnabled;
        } else {
          obj[key] = this.aclObj[key];
        }
      }
      this.aclObj = obj;
    },
    onPermissionChange(isEnabled, name) {
      this.edited = true;
      if (isEnabled && !this.aclRoleOpAll[name]) {
        this.$set(this.aclRoleOpAll, name, true);
      }
      if (!isEnabled && this.aclRoleOpAll[name]) {
        this.$set(
          this.aclRoleOpAll,
          name,
          Object.entries(this.aclObj).some(([key, enabled]) => key.endsWith(name) && enabled)
        );
      }
    },
  },
  // watch: {
  //   aclRoleOpAll: {
  //     // todo: fix toggle issue
  //     handler(aclRoleOpAll) {
  //       const obj = {};
  //       for (const key in this.aclObj) {
  //         obj[key] = aclRoleOpAll[key.split('___').slice(1).join('___')];
  //       }
  //       this.aclObj = obj;
  //     },
  //     deep: true
  //   }
  //
  // }
};
</script>

<style scoped lang="scss">
tr,
th {
  border: 1px solid grey;
}

td,
th {
  border-left: 1px solid grey;
}

td:last-child,
th:last-child {
  border-right: 1px solid grey;
}

tr:first-child > th:nth-child(n + 2) {
  border-bottom: 1px solid grey;
}

th.permission {
  padding-left: 0;
  padding-right: 0;
  /*width: 75px;*/
}

//.permission-checkbox-container {
//  transition: filter .4s;
//  filter: grayscale(100%);
//}
//
//.permission-checkbox-container:hover {
//  filter: none;
//}

::v-deep {
  .permission-checkbox-container .v-input {
    transform: scale(0.8);
  }

  .v-overlay__content {
    height: 100%;
    display: flex;
    align-items: center;
  }

  table {
    border-collapse: collapse;
  }
}

.role-op-header {
  position: relative;

  .custom-acl {
    opacity: 0;
    transition: opacity 0.4s;
    position: absolute;
    right: 1px;
    bottom: 1px;
  }

  .custom-acl-found {
    position: absolute;
    right: 1px;
    top: 1px;
  }

  &:hover .custom-acl {
    opacity: 1;
  }
}
</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/>.
 *
 */
-->