<script setup>
/**
 * Manage users — TLP-style B2CDataTable (filters drawer, column picker, toolbar icons).
 */
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 { ACTIVE_INACTIVE_BADGES } from "../../constants/badgeStyles.js";
import { api, ensureCsrf } from "../../services/api";
import { useAuth } from "../../composables/useAuth";

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

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

const { permissions } = useAuth();

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

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

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

const canAssignRoles = computed(() =>
  (permissions.value ?? []).includes("users.assign-roles"),
);

const users = ref([]);
const rolesCatalog = ref([]);
const loading = ref(false);
const error = ref("");
const dialogVisible = ref(false);
const editing = ref(null);

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

const draft = ref({
  name: "",
  email: "",
  password: "",
  is_active: true,
  roles: [],
});

const columns = computed(() => {
  const cols = [
    {
      key: "name",
      header: "Name",
      type: "text",
      searchable: true,
      filterable: true,
      sortable: true,
    },
    {
      key: "email",
      header: "Email",
      type: "text",
      searchable: true,
      filterable: true,
      sortable: true,
    },
  ];
  if (canAssignRoles.value) {
    cols.push({
      key: "roles_txt",
      header: "Roles",
      type: "text",
      searchable: true,
      filterable: false,
      sortable: false,
      filterKey: "roles_txt",
    });
  }
  cols.push({
    key: "is_active",
    header: "Active",
    type: "badge",
    filterType: "boolean",
    searchable: false,
    filterable: true,
    sortable: true,
    valueMap: ACTIVE_INACTIVE_BADGES,
    defaultBadgeEntry: ACTIVE_INACTIVE_BADGES.false,
  });

  return cols;
});

const tableRows = computed(() =>
  (users.value ?? []).map((u) => ({
    ...u,
    roles_txt: (u.roles ?? []).join(", "),
  })),
);

async function bootstrap() {
  loading.value = true;
  error.value = "";
  try {
    await ensureCsrf();
    const [usersRes, rolesRes] = await Promise.all([
      api.get("/api/users"),
      api.get("/api/roles"),
    ]);
    users.value = usersRes.data?.data ?? [];

    const rows = rolesRes.data?.data ?? [];
    rolesCatalog.value = Array.isArray(rows)
      ? rows.map((r) => r.name).filter(Boolean)
      : [];
  } catch (e) {
    error.value =
      e?.response?.data?.message ?? "Could not load users or roles list.";
    users.value = [];
  } finally {
    loading.value = false;
  }
}

onMounted(bootstrap);

function openCreate() {
  editing.value = null;
  errors.value = {};
  draft.value = {
    name: "",
    email: "",
    password: "",
    is_active: true,
    roles: [],
  };
  dialogVisible.value = true;
}

function openEdit(row) {
  editing.value = row;
  errors.value = {};
  draft.value = {
    name: row.name ?? "",
    email: row.email ?? "",
    password: "",
    is_active: !!row.is_active,
    roles: [...(row.roles ?? [])],
  };
  dialogVisible.value = true;
}

function closeDialog() {
  dialogVisible.value = false;
}

function fieldError(field) {
  const e = errors.value[field];
  return Array.isArray(e) ? e[0] : e ?? "";
}

async function saveUser() {
  saving.value = true;
  errors.value = {};
  try {
    await ensureCsrf();

    /** @type {Record<string, unknown>} */
    const payload = {
      name: draft.value.name.trim(),
      email: draft.value.email.trim(),
      is_active: !!draft.value.is_active,
    };

    if (canAssignRoles.value) {
      payload.roles = [...(draft.value.roles ?? [])];
    }

    if (!editing.value) {
      payload.password = draft.value.password;
      const { data } = await api.post("/api/users", payload);
      const row = data.data;
      users.value = [...users.value.filter((u) => u.id !== row.id), row].sort(
        (a, b) => String(a.name).localeCompare(String(b.name)),
      );
      dialogVisible.value = false;

      return;
    }

    if (draft.value.password) {
      payload.password = draft.value.password;
    }

    const { data } = await api.patch(`/api/users/${editing.value.id}`, payload);
    const row = data.data;
    users.value = users.value
      .map((u) => (u.id === row.id ? row : u))
      .sort((a, b) => String(a.name).localeCompare(String(b.name)));
    dialogVisible.value = false;
  } catch (e) {
    errors.value =
      e?.response?.data?.errors ?? e?.response?.data?.validation ?? {};
    if (!Object.keys(errors.value).length) {
      errors.value.form = [e?.response?.data?.message ?? "Save failed."];
    }
  } finally {
    saving.value = false;
  }
}

async function removeUser(row) {
  if (
    typeof window !== "undefined" &&
    !window.confirm(`Delete ${row.email}? This cannot be undone.`)
  ) {
    return;
  }
  try {
    await ensureCsrf();
    await api.delete(`/api/users/${row.id}`);
    users.value = users.value.filter((u) => u.id !== row.id);
  } catch (e) {
    error.value = e?.response?.data?.message ?? "Could not delete user.";
  }
}
</script>

<template>
  <BaseIndex flush hide-header>
    <Message v-if="errors.form?.[0]" severity="error" class="rounded-2xl mb-3"
      >{{ errors.form?.[0] }}</Message
    >

    <B2CDataTable
      table-key="settings.users"
      :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="user"
      resource-label-plural="users"
    >
      <template #toolbar-title>
        <div>
          <h1
            class="text-2xl font-semibold tracking-tight text-surface-950 dark:text-surface-0 m-0"
          >
            Users
          </h1>
          <p
            class="text-sm text-surface-600 dark:text-surface-400 mt-1.5 mb-0 max-w-3xl"
          >
            Invite and manage dashboard users inside your organisation.
          </p>
        </div>
      </template>
      <template #controls-left>
        <BaseButton
          v-if="canCreate"
          variant="primary"
          icon="plus"
          class="shrink-0"
          @click="openCreate"
        >
          Add user
        </BaseButton>
      </template>

      <template v-if="canAssignRoles" #cell-roles_txt="{ row }">
        <div class="flex flex-wrap gap-1 max-w-md">
          <Tag
            v-for="r in row.roles ?? []"
            :key="r"
            :value="r"
            severity="secondary"
          />
        </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="Edit user"
            @click="openEdit(row)"
          />
          <Button
            v-if="canDelete"
            type="button"
            icon="pi pi-trash"
            rounded
            text
            severity="danger"
            size="small"
            class="shrink-0"
            aria-label="Delete user"
            @click="removeUser(row)"
          />
        </div>
      </template>
    </B2CDataTable>

    <Dialog
      v-model:visible="dialogVisible"
      modal
      :header="editing ? 'Edit user' : 'New user'"
      class="w-full max-w-lg"
      :dismissable-mask="true"
      @hide="closeDialog"
    >
      <form class="flex flex-col gap-4 mt-4" @submit.prevent="saveUser">
        <BaseInputText
          id="uv-name"
          v-model.trim="draft.name"
          fluid
          label="Name"
          required
          :error="fieldError('name')"
        />
        <BaseInputText
          id="uv-email"
          v-model.trim="draft.email"
          fluid
          type="email"
          label="Email"
          required
          :error="fieldError('email')"
        />
        <BaseInputText
          id="uv-password"
          v-model="draft.password"
          fluid
          type="password"
          :description="editing ? 'Leave blank to keep current.' : ''"
          :label="editing ? 'Password (optional)' : 'Password'"
          :required="!editing"
          :error="fieldError('password')"
        />

        <div class="flex items-center gap-2">
          <Checkbox v-model="draft.is_active" binary input-id="uv-active" />
          <label for="uv-active" class="label-small cursor-pointer">
            Active
          </label>
        </div>

        <div v-if="canAssignRoles" class="flex flex-col gap-2">
          <label class="label-small">Roles</label>
          <MultiSelect
            v-model="draft.roles"
            :options="rolesCatalog"
            display="chip"
            placeholder="Roles"
            class="w-full"
          />
          <Message
            v-if="fieldError('roles')"
            severity="error"
            class="text-xs"
            >{{ fieldError("roles") }}</Message
          >
        </div>

        <div class="flex justify-end gap-3 pt-2">
          <BaseButton variant="secondary" type="button" @click="closeDialog">
            Cancel
          </BaseButton>
          <BaseButton variant="primary" type="submit" :loading="saving">
            Save
          </BaseButton>
        </div>
      </form>
    </Dialog>
  </BaseIndex>
</template>
