<template>
  <div
    class="flex flex-col gap-2 max-w-2xl mx-auto w-full select-none"
    :class="disableEdit ? ' pointer-events-none opacity-60 bg-gray-100/50' : ''"
  >
    <div class="flex flex-row gap-2 h-fit w-full border border-gray-300 rounded-md p-2">
      <input type="checkbox" name="admin" id="admin" class="cursor-pointer" :checked="isAdmin" @change="toggleAdmin" />
      <label for="admin" class="cursor-pointer">Administratorrecht</label>
    </div>
    <div
      v-for="section in sections"
      :key="section"
      class="flex flex-col gap-2 h-fit w-full border border-primary rounded-md"
      :class="isAdmin && !disableEdit ? ' pointer-events-none opacity-60 bg-gray-100' : ''"
    >
      <div class="bg-primary p-2 text-white flex flex-row justify-between items-center">
        <p>Abschnitt: {{ section }}</p>
        <div class="flex flex-row border border-white rounded-md overflow-hidden">
          <EyeIcon
            class="w-5 h-5 p-1 box-content cursor-pointer"
            :class="_can(permissionUpdate, 'read', section) ? 'bg-success' : ''"
            @click="togglePermission('read', section)"
          />
          <PlusIcon
            class="w-5 h-5 p-1 box-content cursor-pointer"
            :class="_can(permissionUpdate, 'create', section) ? 'bg-success' : ''"
            @click="togglePermission('create', section)"
          />
          <PencilIcon
            class="w-5 h-5 p-1 box-content cursor-pointer"
            :class="_can(permissionUpdate, 'update', section) ? 'bg-success' : ''"
            @click="togglePermission('update', section)"
          />
          <TrashIcon
            class="w-5 h-5 p-1 box-content cursor-pointer"
            :class="_can(permissionUpdate, 'delete', section) ? 'bg-success' : ''"
            @click="togglePermission('delete', section)"
          />
        </div>
      </div>
      <div
        v-for="modul in permissionStructure[section]"
        :key="modul"
        class="p-1 px-2 flex flex-row justify-between items-center"
      >
        <p>Modul: {{ modul }}</p>
        <div class="flex flex-row border border-gray-300 rounded-md overflow-hidden">
          <EyeIcon
            class="w-5 h-5 p-1 box-content cursor-pointer"
            :class="_can(permissionUpdate, 'read', section, modul) ? 'bg-success' : ''"
            @click="togglePermission('read', section, modul)"
          />
          <PlusIcon
            class="w-5 h-5 p-1 box-content cursor-pointer"
            :class="_can(permissionUpdate, 'create', section, modul) ? 'bg-success' : ''"
            @click="togglePermission('create', section, modul)"
          />
          <PencilIcon
            class="w-5 h-5 p-1 box-content cursor-pointer"
            :class="_can(permissionUpdate, 'update', section, modul) ? 'bg-success' : ''"
            @click="togglePermission('update', section, modul)"
          />
          <TrashIcon
            class="w-5 h-5 p-1 box-content cursor-pointer"
            :class="_can(permissionUpdate, 'delete', section, modul) ? 'bg-success' : ''"
            @click="togglePermission('delete', section, modul)"
          />
        </div>
      </div>
    </div>
    <div v-if="!disableEdit" class="flex flex-row gap-2 self-end pt-4">
      <button primary-outline class="!w-fit" @click="reset" :disabled="canSaveOrReset">verwerfen</button>
      <button primary class="!w-fit" @click="submit" :disabled="status == 'loading' || canSaveOrReset">
        speichern
      </button>
      <Spinner v-if="status == 'loading'" class="my-auto" />
      <SuccessCheckmark v-else-if="status?.status == 'success'" />
      <FailureXMark v-else-if="status?.status == 'failed'" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { defineComponent } from "vue";
import type { PropType } from "vue";
import type {
  PermissionModule,
  PermissionObject,
  PermissionSection,
  PermissionType,
  SectionsAndModulesObject,
} from "@/types/permissionTypes";
import { sectionsAndModules, permissionSections, permissionTypes } from "@/types/permissionTypes";
import { mapState, mapActions } from "pinia";
import { EyeIcon, PencilIcon, PlusIcon, TrashIcon } from "@heroicons/vue/24/outline";
import { useAbilityStore } from "@/stores/ability";
import cloneDeep from "lodash.clonedeep";
import isEqual from "lodash.isEqual";
import Spinner from "@/components/Spinner.vue";
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
import FailureXMark from "@/components/FailureXMark.vue";
</script>

<script lang="ts">
export default defineComponent({
  props: {
    permissions: {
      type: Object as PropType<PermissionObject>,
      default: {},
    },
    status: {
      type: [Object, String, null] as PropType<null | "loading" | { status: "success" | "failed"; message?: string }>,
      default: null,
    },
    disableEdit: {
      type: Boolean,
      default: false,
    },
  },
  watch: {
    permissions() {
      this.permissionUpdate = cloneDeep(this.permissions);
    },
  },
  emits: ["savePermissions"],
  data() {
    return {
      isAdmin: false,
      sections: [] as Array<PermissionSection>,
      permissionStructure: {} as SectionsAndModulesObject,
      permissionUpdate: {} as PermissionObject,
    };
  },
  computed: {
    ...mapState(useAbilityStore, ["_can"]),
    canSaveOrReset(): boolean {
      return isEqual(this.permissions, this.permissionUpdate);
    },
  },
  mounted() {
    this.sections = permissionSections;
    this.permissionStructure = sectionsAndModules;
    this.permissionUpdate = cloneDeep(this.permissions);

    this.isAdmin = this.permissions.admin ?? false;
  },
  methods: {
    toggleAdmin(e: Event) {
      const target = e.target as HTMLInputElement;
      this.isAdmin = target.checked ?? false;
      this.permissionUpdate.admin = this.isAdmin;
      if (!this.isAdmin) {
        delete this.permissionUpdate.admin;
      }
    },
    togglePermission(type: PermissionType, section: PermissionSection, modul?: PermissionModule) {
      let permissions = [] as Array<PermissionType> | "*";
      if (!modul) {
        permissions = this.permissionUpdate[section]?.all ?? [];
      } else {
        permissions = this.permissionUpdate[section]?.[modul] ?? [];
      }

      if (permissions == "*") {
        permissions = permissionTypes;
      }

      if (permissions.includes(type)) {
        let add = permissions.slice(-1)[0] == type ? 0 : 1;
        let whatToRemove = permissionTypes.slice(permissionTypes.indexOf(type) + add);
        permissions = permissions.filter((permission) => !whatToRemove.includes(permission));
      } else {
        let whatToAdd = permissionTypes.slice(0, permissionTypes.indexOf(type) + 1);
        permissions = whatToAdd;
      }

      if (!modul) {
        if (!this.permissionUpdate[section]) {
          this.permissionUpdate[section] = {};
        }
        this.permissionUpdate[section].all = permissions;
      } else {
        if (!this.permissionUpdate[section]) {
          this.permissionUpdate[section] = {};
        }
        this.permissionUpdate[section][modul] = permissions;
      }
    },
    reset() {
      this.permissionUpdate = cloneDeep(this.permissions);
      this.isAdmin = this.permissions.admin ?? false;
    },
    submit() {
      this.$emit("savePermissions", this.permissionUpdate);
    },
  },
});
</script>
