<template>
  <v-row no-gutters>
    <v-col cols="12" class="mb-2">
      <v-row no-gutters>
        <v-btn
          class="text-none"
          rounded="pill"
          variant="tonal"
          @click="createDialog = true"
          size="large"
          v-if="canCreateRole"
        >
          Create role
        </v-btn>
      </v-row>
    </v-col>
    <v-col cols="12">
      <v-card
        width="100%"
        variant="outlined"
        border="thin"
        rounded="lg"
        :loading="loading"
      >
        <v-toolbar density="compact" color="grey-lighten-4">
          <template #prepend>
            <v-btn fab icon density="comfortable" @click="getRoles()">
              <v-icon>mdi-refresh</v-icon>
            </v-btn>
          </template>

          <template #append>
            <v-row no-gutters justify="end" align="center">
              <span class="mr-2 text-caption text-fontgray">
                {{ pageRange }}
              </span>
              <local-pagination
                v-model="page"
                :length="pages"
                @update:value="getRoles()"
              />
            </v-row>
          </template>
        </v-toolbar>

        <v-data-table
          :headers="props.headers"
          :items="items"
          item-value="_id"
          items-per-page="20"
          fixed-header
          hide-default-footer
          hide-default-header
          @click:row="tableRowClickHandler"
          style="max-height: calc(100vh - (180px))"
        >
          <template #item.permissions="{ value }">
            <span class="text-caption font-weight-bold text-capitalize">
              permissions
            </span>
            <v-chip>{{ value.length }}</v-chip>
          </template>

          <template #item.action-table="{ item }" v-if="canDeleteRole">
            <v-menu :close-on-content-click="false" offset-y width="150">
              <template v-slot:activator="{ props }">
                <v-icon v-bind="props">mdi-dots-horizontal</v-icon>
              </template>
              <v-list>
                <v-list-item @click="openDeleteDialog(item._id)">
                  Delete Role
                </v-list-item>
              </v-list>
            </v-menu>
          </template>
        </v-data-table>
      </v-card>
    </v-col>

    <!-- dialogs -->
    <v-dialog v-model="createDialog" width="500" persistent>
      <RolePermissionFormCreate
        @cancel="createDialog = false"
        :permissions="props.permissions"
        :org="props.orgId"
        :site-id="props.siteId"
        @success="success()"
        :type="props.type"
        @success:create-more="getRoles()"
      />
    </v-dialog>

    <v-dialog v-model="previewDialog" width="500" persistent>
      <RolePermissionFormPreviewUpdate
        @cancel="previewDialog = false"
        @success="successfulUpdate()"
        :permissions="Permissions"
        :original-permissions="originalPermissions"
        v-model="selectedPermissions"
        v-model:edit="edit"
        :name="name"
        :id="roleId"
      />
    </v-dialog>

    <ConfirmDialog
      v-model="confirmDialog"
      :loading="deleteLoading"
      @submit="handleDeleteRole"
    >
      <template #title>
        <span class="font-weight-medium text-h5">Delete Role</span>
      </template>

      <template #description>
        <p class="text-subtitle-2">
          Are you sure you want to delete this role? This action cannot be
          undone.
        </p>
      </template>

      <template #footer>
        <div class="d-flex justify-center ga-3 w-100">
          <v-btn
            variant="text"
            @click="confirmDialog = false"
            :disabled="deleteLoading"
          >
            Close
          </v-btn>
          <v-btn
            color="primary"
            variant="flat"
            @click="handleDeleteRole"
            :loading="deleteLoading"
          >
            Delete Role
          </v-btn>
        </div>
      </template>
    </ConfirmDialog>

    <Snackbar v-model="messageSnackbar" :text="message" :color="messageColor" />
  </v-row>
</template>

<script setup lang="ts">
const props = defineProps({
  orgId: {
    type: String,
    default: "",
  },
  customerId: {
    type: String,
    default: "",
  },
  siteId: {
    type: String,
    default: "",
  },
  type: {
    type: String,
    required: true,
    default: "app",
  },
  permissions: {
    type: Object,
    required: true,
    default: () => ({}),
  },
  headers: {
    type: Array as PropType<Array<Record<string, any>>>,
    default: () => [
      {
        title: "name",
        value: "name",
      },
      {
        title: "permissions",
        value: "permissions",
      },
      { title: "Action", value: "action-table" },
    ],
  },
  canCreateRole: {
    type: Boolean,
    default: false,
  },
  canViewRole: {
    type: Boolean,
    default: false,
  },
  canViewByRole: {
    type: Boolean,
    default: false,
  },
  canDeleteRole: {
    type: Boolean,
    default: false,
  },
  canUpdateRole: {
    type: Boolean,
    default: false,
  },
});

const { headerSearch } = useLocal();

const { getRoles: _getRoles } = useRole();

const page = ref(1);
const pages = ref(0);
const pageRange = ref("-- - -- of --");

const message = ref("");
const messageSnackbar = ref(false);
const messageColor = ref("");

const items = ref<Array<Record<string, any>>>([]);

const {
  data: getRoleReq,
  refresh: getRoles,
  status: getRoleReqStatus,
} = useLazyAsyncData(
  "roles-permissions-get-all",
  () =>
    _getRoles({
      page: page.value,
      search: headerSearch.value,
      type: props.type,
      org: props.orgId,
    }),
  {
    watch: [page, headerSearch],
  }
);

const loading = computed(() => getRoleReqStatus.value === "pending");

watchEffect(() => {
  if (getRoleReq.value) {
    items.value = getRoleReq.value.items;
    pages.value = getRoleReq.value.pages;
    pageRange.value = getRoleReq.value.pageRange;
  }
});

function tableRowClickHandler(_: any, data: any) {
  previewDialog.value = true;
  roleId.value = data.item._id;
}

const createDialog = ref(false);

function success() {
  createDialog.value = false;
  getRoles();
}

const previewDialog = ref(false);

const name = ref("");
const selectedPermissions = ref<Array<string>>([]);
const originalPermissions = ref<Array<string>>([]);
const edit = ref(false);

const { convertPermissionsToArray } = useUtils();

const roleId = ref("");

const { getRoleById: _getRoleById, deleteRole } = useRole();

const { data: role, refresh: getRoleById } = useLazyAsyncData(
  "role-permissions-get-by-id",
  () => _getRoleById(roleId.value)
);

watchEffect(() => {
  if (roleId.value) {
    getRoleById();
  }
});

watchEffect(() => {
  if (role.value) {
    name.value = role.value.name;

    selectedPermissions.value = role.value.permissions;
    originalPermissions.value = role.value.permissions;
  }
});

function filterPermissions(
  allPermissions: TPermissions,
  storedPermissions: string[]
) {
  const filteredPermissions: TPermissions = {};

  if (!allPermissions || typeof allPermissions !== "object")
    return filteredPermissions;

  Object.entries(allPermissions).forEach(([resource, actions]) => {
    if (!actions || typeof actions !== "object") return;
    const filteredActions = Object.entries(actions)
      .filter(([action]) => storedPermissions.includes(`${resource}:${action}`))
      .reduce((acc: Record<string, any>, [action, data]) => {
        acc[action] = data;
        return acc;
      }, {});

    if (Object.keys(filteredActions).length > 0) {
      filteredPermissions[resource] = filteredActions;
    }
  });

  return filteredPermissions;
}

const Permissions = computed(() => {
  return edit.value
    ? props.permissions
    : filterPermissions(props.permissions, originalPermissions.value);
});

function successfulUpdate() {
  previewDialog.value = false;
  getRoles();
  useLocalSetup(props.type);
}

const confirmDialog = ref(false);
const selectedRoleId = ref<string | null>(null);
const deleteLoading = ref(false);

function openDeleteDialog(id: string) {
  selectedRoleId.value = id;
  confirmDialog.value = true;
}

function showMessage(msg: string, color: string) {
  message.value = msg;
  messageColor.value = color;
  messageSnackbar.value = true;
}

async function handleDeleteRole() {
  if (!selectedRoleId.value) return;
  deleteLoading.value = true;
  try {
    const res = await deleteRole(selectedRoleId.value);

    confirmDialog.value = false;
    showMessage(res.message, "success");
    getRoles();
  } catch (error: any) {
    const errorMessage = error?.response?._data?.message;
    showMessage(errorMessage, "error");
  } finally {
    deleteLoading.value = false;
    selectedRoleId.value = null;
  }
}
</script>
