<script setup>
/**
 * Roles — B2CDataTable /api/roles + /api/permissions (Spatie).
 */
import BaseButton from "../../components/base/BaseButton.vue";
import BaseIndex from "../../components/base/BaseIndex.vue";
import BaseInputText from "../../components/base/BaseInputText.vue";
import B2CDataTable from "../../components/common/B2CDataTable.vue";

import Button from "primevue/button";
import Dialog from "primevue/dialog";
import Message from "primevue/message";
import MultiSelect from "primevue/multiselect";
import Tag from "primevue/tag";

import { useAuth } from "../../composables/useAuth";
import { api, ensureCsrf } from "../../services/api";

import { computed, onMounted, ref } from "vue";

const { permissions } = useAuth();

const canCreate = computed(() =>
  (permissions.value ?? []).includes("roles.create"),
);

const canEdit = computed(() => (permissions.value ?? []).includes("roles.edit"));

const canDelete = computed(() =>
  (permissions.value ?? []).includes("roles.delete"),
);

const roles = ref([]);
const permCatalog = ref([]);

const loading = ref(false);
const error = ref("");
const dialogVisible = ref(false);
const dialogMode = ref("create"); // create | edit
const editingRole = ref(null);

const draftName = ref("");
const draftPerms = ref([]);

const saving = ref(false);
const validation = ref({});

const columns = [
  {
    key: "name",
    header: "Naam",
    type: "text",
    searchable: true,
    filterable: true,
    sortable: true,
  },
  {
    key: "permissions",
    header: "Permissions",
    type: "text",
    searchable: true,
    filterKey: "perm_search",
    filterable: false,
    sortable: false,
  },
];

const tableRows = computed(() =>
  (roles.value ?? []).map((r) => ({
    ...r,
    perm_search: (r.permissions ?? []).join(" "),
  })),
);

async function bootstrap() {
  loading.value = true;
  error.value = "";
  try {
    await ensureCsrf();

    const [r, p] = await Promise.all([
      api.get("/api/roles"),
      api.get("/api/permissions"),
    ]);

    roles.value = r.data?.data ?? [];
    permCatalog.value = p.data?.data ?? [];
  } catch (e) {
    error.value =
      e?.response?.data?.message ?? "Could not load roles or permissions.";
  } finally {
    loading.value = false;
  }
}

onMounted(bootstrap);

function openCreate() {
  dialogMode.value = "create";
  editingRole.value = null;
  draftName.value = "";
  draftPerms.value = [];
  validation.value = {};
  dialogVisible.value = true;
}

function openEdit(role) {
  dialogMode.value = "edit";
  editingRole.value = role;
  draftName.value = role.name ?? "";
  draftPerms.value = [...(role.permissions ?? [])];
  validation.value = {};
  dialogVisible.value = true;
}

async function saveRole() {
  if (dialogMode.value === "edit" && editingRole.value?.name === "admin") {
    dialogVisible.value = false;

    return;
  }

  saving.value = true;
  validation.value = {};

  try {
    await ensureCsrf();

    if (dialogMode.value === "create") {
      await api.post("/api/roles", {
        name: draftName.value.trim(),
        permissions: draftPerms.value,
      });
    } else if (editingRole.value) {
      await api.put(`/api/roles/${editingRole.value.id}`, {
        name: draftName.value.trim(),
        permissions: draftPerms.value,
      });
    }

    dialogVisible.value = false;
    await bootstrap();
  } catch (e) {
    validation.value = e?.response?.data?.errors ?? {};
    if (
      typeof e?.response?.data?.message === "string" &&
      Object.keys(validation.value).length === 0
    ) {
      error.value = e.response.data.message;
    }
  } finally {
    saving.value = false;
  }
}

async function destroyRole(role) {
  if (role.name === "admin") return;

  if (
    typeof window !== "undefined" &&
    !window.confirm(`Remove role "${role.name}"?`)
  ) {
    return;
  }

  try {
    await ensureCsrf();
    await api.delete(`/api/roles/${role.id}`);
    roles.value = roles.value.filter((r) => r.id !== role.id);
  } catch (e) {
    error.value =
      e?.response?.data?.message ?? "Can't delete role (still assigned?).";
  }
}
</script>

<template>
  <BaseIndex flush hide-header>
    <B2CDataTable
      table-key="settings.roles"
      :columns="columns"
      :rows="tableRows"
      :loading="loading"
      :persist-to-server="true"
      :paginator="true"
      :rows-per-page="10"
      :rows-per-page-options="[10, 25, 50]"
      :enable-export="false"
      :show-actions="canEdit || canDelete"
      search-placeholder="Zoeken…"
      :table-error="error"
      resource-label-singular="rol"
      resource-label-plural="rollen"
    >
      <template #toolbar-title>
        <div>
          <h1
            class="text-2xl font-semibold tracking-tight text-surface-950 dark:text-surface-0 m-0"
          >
            Rollen
          </h1>
          <p
            class="text-sm text-surface-600 dark:text-surface-400 mt-1.5 mb-0 max-w-3xl"
          >
            Define roles and connect them to abilities (Spatie).
          </p>
        </div>
      </template>
      <template #controls-left>
        <BaseButton
          v-if="canCreate"
          variant="primary"
          icon="plus"
          label="Nieuwe rol"
          class="shrink-0"
          @click="openCreate"
        />
      </template>

      <template #cell-permissions="{ row }">
        <div class="flex flex-wrap gap-1 max-w-xl">
          <Tag
            v-for="perm in (row.permissions ?? []).slice(0, 12)"
            :key="`${row.id}:${perm}`"
            severity="secondary"
            :value="String(perm)"
          />
          <span
            v-if="(row.permissions ?? []).length > 12"
            class="text-xs text-surface-500 px-2"
          >
            (+{{ (row.permissions ?? []).length - 12 }} more)
          </span>
        </div>
      </template>

      <template v-if="canEdit || canDelete" #actions="{ row }">
        <div class="flex flex-nowrap items-center justify-end gap-1">
          <Button
            v-if="canEdit"
            type="button"
            icon="pi pi-pencil"
            rounded
            text
            severity="secondary"
            size="small"
            class="shrink-0"
            aria-label="Rol bewerken"
            @click="openEdit(row)"
          />
          <Button
            v-if="canDelete && row.name !== 'admin'"
            type="button"
            icon="pi pi-trash"
            rounded
            text
            severity="danger"
            size="small"
            class="shrink-0"
            aria-label="Rol verwijderen"
            @click="destroyRole(row)"
          />
        </div>
      </template>
    </B2CDataTable>

    <Dialog
      v-model:visible="dialogVisible"
      modal
      :header="dialogMode === 'create' ? 'Nieuwe rol' : 'Rol bewerken'"
      class="w-full max-w-2xl"
    >
      <form class="flex flex-col gap-4 mt-2" @submit.prevent="saveRole">
        <BaseInputText
          v-if="dialogMode === 'create' || editingRole?.name !== 'admin'"
          v-model.trim="draftName"
          label="Rol naam"
          required
          fluid
          :disabled="dialogMode === 'edit' && editingRole?.name === 'admin'"
        />

        <div
          v-if="dialogMode === 'edit' && editingRole?.name === 'admin'"
          class="text-sm text-surface-500"
        >
          De built-in rol <strong>admin</strong> heeft vaste rechten via seed —
          naam en rechtenlijst worden niet gewijzigd via deze dialoog.
        </div>

        <template
          v-if="
            dialogMode === 'create' ||
            (dialogMode === 'edit' && editingRole?.name !== 'admin')
          "
        >
          <label class="label-small text-surface-600 dark:text-surface-300">
            Permissions
          </label>
          <MultiSelect
            v-model="draftPerms"
            filter
            :options="permCatalog"
            display="chip"
            placeholder="Kies rechten"
            class="w-full max-h-[20rem]"
          />
          <Message v-if="validation.permissions" severity="error" size="small">
            {{ validation.permissions.join?.("") ?? validation.permissions }}
          </Message>
        </template>

        <Message v-if="validation.name" severity="error">
          {{
            Array.isArray(validation.name) ? validation.name[0] : validation.name
          }}
        </Message>

        <div class="flex justify-end gap-2 pt-4">
          <BaseButton
            variant="secondary"
            outlined
            icon="cancel"
            type="button"
            @click="dialogVisible = false"
          >
            Annuleren
          </BaseButton>
          <BaseButton
            v-if="dialogMode === 'edit' && editingRole?.name === 'admin'"
            variant="secondary"
            outlined
            icon="cancel"
            type="button"
            @click="dialogVisible = false"
          >
            Sluiten
          </BaseButton>
          <BaseButton
            v-if="dialogMode !== 'edit' || editingRole?.name !== 'admin'"
            variant="primary"
            icon="check"
            type="submit"
            :loading="saving"
          >
            Opslaan
          </BaseButton>
        </div>
      </form>
    </Dialog>
  </BaseIndex>
</template>
