<script lang="ts">
  import { enhance } from "$app/forms";
  import type { SubmitFunction } from "@sveltejs/kit";
  import type { User } from "$lib/optima-api/modules/users";
  import type { Role } from "$lib/optima-api/modules/roles";
  import type {
    PermissionsCategorized,
    PermissionCategory,
    PermissionNode,
  } from "$lib/optima-api/modules/permissions";
  import {
    collectAllNodes,
    collectAllPermNodes,
    allSelectableStrings,
  } from "$lib/permissions";

  type UserWithRoles = User & { roleDetails: Role[] };

  export let user: UserWithRoles;
  export let allRoles: Role[] = [];
  export let permissionNodes: PermissionsCategorized = {};
  export let canEditRoles = false;
  export let canEditPermissions = false;
  export let onClose: () => void = () => {};
  export let onSuccess: () => void = () => {};

  const initialComputedName =
    `${user.firstName ?? ""} ${user.lastName ?? ""}`.trim();
  const displayName =
    initialComputedName || user.name || user.login || user.email;

  let editFirstName = user.firstName ?? "";
  let editLastName = user.lastName ?? "";
  let editImage = user.image ?? "";
  let editError = "";
  let isEditing = false;

  // Role editing
  let editSelectedRoles: string[] = user.roleDetails.map((r) => r.id);

  // Permission editing
  let editSelectedPermissions: string[] = [...(user.permissions ?? [])];
  let permSearchQuery = "";
  let customPermNode = "";
  let customPermError = "";

  // Track custom-added nodes so they appear in the list
  let customNodes: string[] = [];

  // Expanded category state for the hierarchical permission view
  let expandedCategories = new Set<string>();

  $: allPermissionNodeStrings = Object.values(permissionNodes ?? {}).flatMap(
    (cat) => collectAllNodes(cat as PermissionCategory)
  );

  $: allPermissionNodesWithCustom = [
    ...allPermissionNodeStrings,
    ...customNodes.filter((n) => !allPermissionNodeStrings.includes(n)),
  ];

  $: permissionEntries = Object.entries(permissionNodes ?? {}) as [
    string,
    PermissionCategory,
  ][];

  // Initialize expanded categories to those containing selected permissions
  $: {
    const sel = new Set(editSelectedPermissions);
    if (sel.size > 0 && expandedCategories.size === 0) {
      const expanded = new Set<string>();
      for (const [key, cat] of permissionEntries) {
        if (collectAllNodes(cat).some((n) => sel.has(n))) {
          expanded.add(key);
        }
        if (cat.subCategories) {
          for (const [subKey, subCat] of Object.entries(cat.subCategories) as [
            string,
            PermissionCategory,
          ][]) {
            if (collectAllNodes(subCat).some((n) => sel.has(n))) {
              expanded.add(`${key}/${subKey}`);
            }
          }
        }
      }
      expandedCategories = expanded;
    }
  }

  function toggleCategory(key: string) {
    const next = new Set(expandedCategories);
    next.has(key) ? next.delete(key) : next.add(key);
    expandedCategories = next;
  }

  function toggleAllInCategory(perms: PermissionNode[]) {
    const all = allSelectableStrings(perms);
    const allSelected = all.every((s) => editSelectedPermissions.includes(s));
    if (allSelected) {
      const removeSet = new Set(all);
      editSelectedPermissions = editSelectedPermissions.filter(
        (p) => !removeSet.has(p)
      );
    } else {
      const existing = new Set(editSelectedPermissions);
      for (const s of all) {
        existing.add(s);
      }
      editSelectedPermissions = [...existing];
    }
  }

  function toggleFieldLevelPerms(fieldPerms: string[]) {
    const allSelected = fieldPerms.every((f) =>
      editSelectedPermissions.includes(f)
    );
    if (allSelected) {
      const removeSet = new Set(fieldPerms);
      editSelectedPermissions = editSelectedPermissions.filter(
        (p) => !removeSet.has(p)
      );
    } else {
      const existing = new Set(editSelectedPermissions);
      for (const f of fieldPerms) {
        existing.add(f);
      }
      editSelectedPermissions = [...existing];
    }
  }

  function toggleEditRole(id: string) {
    if (editSelectedRoles.includes(id)) {
      editSelectedRoles = editSelectedRoles.filter((r) => r !== id);
    } else {
      editSelectedRoles = [...editSelectedRoles, id];
    }
  }

  function toggleEditPermission(node: string) {
    if (editSelectedPermissions.includes(node)) {
      editSelectedPermissions = editSelectedPermissions.filter(
        (p) => p !== node
      );
    } else {
      editSelectedPermissions = [...editSelectedPermissions, node];
    }
  }

  function addCustomPermission() {
    const node = customPermNode.trim();
    customPermError = "";
    if (!node) return;
    // Validate permission node format per PERMISSIONS.md:
    // - dot-separated tokens of lowercase alphanumeric + underscores
    // - special tokens: * (wildcard), ? (single-char wildcard)
    // - inclusive list [a,b,c] or exclusive list <a,b,c>
    // - standalone * for full access
    if (
      !/^(?:\*|(?:(?:[a-z0-9_]+|\*|\?|\[[a-z0-9_]+(?:,[a-z0-9_]+)*\]|<[a-z0-9_]+(?:,[a-z0-9_]+)*>)(?:\.(?:[a-z0-9_]+|\*|\?|\[[a-z0-9_]+(?:,[a-z0-9_]+)*\]|<[a-z0-9_]+(?:,[a-z0-9_]+)*>))*))$/.test(
        node
      )
    ) {
      customPermError =
        "Use dot-separated tokens (e.g. resource.action). Supports: a-z, 0-9, underscores, * ? wildcards, [a,b] or <a,b> lists.";
      return;
    }
    if (editSelectedPermissions.includes(node)) {
      customPermError = "This permission is already selected.";
      return;
    }
    if (!allPermissionNodesWithCustom.includes(node)) {
      customNodes = [...customNodes, node];
    }
    editSelectedPermissions = [...editSelectedPermissions, node];
    customPermNode = "";
  }

  const handleEditEnhance: SubmitFunction = () => {
    isEditing = true;
    editError = "";
    return async ({ result, update }) => {
      isEditing = false;
      if (result.type === "success") {
        onSuccess();
      } else if (result.type === "failure") {
        editError =
          (result.data as { message?: string })?.message ??
          "Failed to update user.";
      }
      await update();
    };
  };
</script>

<!-- svelte-ignore a11y_no_static_element_interactions -->
<div
  class="confirm-backdrop"
  on:click={onClose}
  on:keydown={(e) => e.key === "Escape" && onClose()}
>
  <div
    class="edit-dialog"
    role="dialog"
    aria-modal="true"
    aria-labelledby="edit-title"
    tabindex="-1"
    on:click|stopPropagation
    on:keydown|stopPropagation
  >
    <h3 id="edit-title" class="edit-dialog-title">Edit User</h3>
    <p class="edit-dialog-sub">
      Update information for <strong>{displayName}</strong>
    </p>
    {#if editError}
      <p class="confirm-error">{editError}</p>
    {/if}
    <form method="POST" action="?/updateUser" use:enhance={handleEditEnhance}>
      <input type="hidden" name="id" value={user.id} />
      {#if canEditRoles}
        <input
          type="hidden"
          name="roles"
          value={JSON.stringify(editSelectedRoles)}
        />
      {/if}
      {#if canEditPermissions}
        <input
          type="hidden"
          name="permissions"
          value={JSON.stringify(editSelectedPermissions)}
        />
      {/if}

      <div class="edit-field">
        <label for="edit-first-name">First Name</label>
        <input
          id="edit-first-name"
          type="text"
          name="firstName"
          bind:value={editFirstName}
        />
      </div>
      <div class="edit-field">
        <label for="edit-last-name">Last Name</label>
        <input
          id="edit-last-name"
          type="text"
          name="lastName"
          bind:value={editLastName}
        />
      </div>
      <div class="edit-field">
        <label for="edit-image">Avatar URL</label>
        <input
          id="edit-image"
          type="text"
          name="image"
          bind:value={editImage}
          placeholder="https://..."
        />
      </div>

      <!-- Role assignment (gated by user.roles.other) -->
      {#if canEditRoles}
        <div class="edit-section">
          <div class="edit-section-label">
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              width="13"
              height="13"
            >
              <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" />
            </svg>
            Roles
            <span class="edit-section-count"
              >{editSelectedRoles.length} selected</span
            >
          </div>
          <div class="edit-role-list">
            {#each allRoles as role (role.id)}
              <button
                type="button"
                class="edit-role-chip"
                class:selected={editSelectedRoles.includes(role.id)}
                on:click={() => toggleEditRole(role.id)}
              >
                <span class="edit-role-check">
                  {#if editSelectedRoles.includes(role.id)}
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2.5"
                      width="12"
                      height="12"
                    >
                      <polyline points="20 6 9 17 4 12" />
                    </svg>
                  {/if}
                </span>
                <span class="edit-role-chip-title">{role.title}</span>
                <span class="edit-role-chip-moniker">{role.moniker}</span>
              </button>
            {/each}
          </div>
        </div>
      {/if}

      <!-- Direct permission assignment (gated by user.permissions.other) -->
      {#if canEditPermissions}
        <div class="edit-section">
          <div class="edit-section-label">
            <svg
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              width="13"
              height="13"
            >
              <path
                d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2"
              />
              <rect x="9" y="3" width="6" height="4" rx="1" />
            </svg>
            Direct Permissions
            <span class="edit-section-count"
              >{editSelectedPermissions.length} selected</span
            >
          </div>

          <!-- Custom permission input -->
          <div class="edit-custom-perm-wrap">
            <input
              type="text"
              class="edit-custom-perm-input"
              placeholder="Add custom node… (e.g. my.custom.node)"
              bind:value={customPermNode}
              on:keydown={(e) =>
                e.key === "Enter" &&
                (e.preventDefault(), addCustomPermission())}
            />
            <button
              type="button"
              class="edit-custom-perm-btn"
              on:click={addCustomPermission}
              disabled={!customPermNode.trim()}
            >
              <svg
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                width="13"
                height="13"
              >
                <line x1="12" y1="5" x2="12" y2="19" />
                <line x1="5" y1="12" x2="19" y2="12" />
              </svg>
              Add
            </button>
          </div>
          {#if customPermError}
            <p class="edit-custom-perm-error">{customPermError}</p>
          {/if}

          <!-- Categorized permission list -->
          <div class="edit-perm-list">
            {#if permissionEntries.length === 0}
              <p class="edit-perm-empty">No permission data available.</p>
            {:else}
              {#each permissionEntries as [catKey, category] (catKey)}
                {@const catPerms = category.permissions ?? []}
                {@const allCatPermNodes = collectAllPermNodes(category)}
                {@const allCatSelectables =
                  allSelectableStrings(allCatPermNodes)}
                {@const allSel =
                  allCatSelectables.length > 0 &&
                  allCatSelectables.every((s) =>
                    editSelectedPermissions.includes(s)
                  )}
                {@const someSel =
                  !allSel &&
                  allCatSelectables.some((s) =>
                    editSelectedPermissions.includes(s)
                  )}
                {@const isExpanded = expandedCategories.has(catKey)}
                {@const hasSubCats =
                  category.subCategories &&
                  Object.keys(category.subCategories).length > 0}
                <div class="edit-cat-group">
                  <div class="edit-cat-header">
                    <button
                      type="button"
                      class="edit-cat-toggle"
                      on:click={() => toggleCategory(catKey)}
                      aria-expanded={isExpanded}
                    >
                      <svg
                        class="chevron"
                        class:rotated={isExpanded}
                        viewBox="0 0 24 24"
                        fill="none"
                        stroke="currentColor"
                        stroke-width="2.5"
                        width="10"
                        height="10"
                      >
                        <polyline points="9 18 15 12 9 6" />
                      </svg>
                      <span class="edit-cat-name">{category.name}</span>
                      <span class="edit-cat-count"
                        >{allCatSelectables.length}</span
                      >
                    </button>
                    <button
                      type="button"
                      class="edit-cat-all-btn"
                      on:click={() => toggleAllInCategory(allCatPermNodes)}
                      title={allSel ? "Deselect all" : "Select all"}
                    >
                      <div
                        class="edit-cb"
                        class:edit-cb-checked={allSel}
                        class:edit-cb-indeterminate={someSel}
                      >
                        {#if allSel}
                          <svg
                            viewBox="0 0 10 10"
                            fill="none"
                            stroke="currentColor"
                            stroke-width="2"
                            width="8"
                            height="8"
                          >
                            <polyline points="1.5 5 4 8 8.5 2" />
                          </svg>
                        {:else if someSel}
                          <svg
                            viewBox="0 0 10 10"
                            fill="none"
                            stroke="currentColor"
                            stroke-width="2.5"
                            width="8"
                            height="8"
                          >
                            <line x1="1.5" y1="5" x2="8.5" y2="5" />
                          </svg>
                        {/if}
                      </div>
                      All
                    </button>
                  </div>

                  {#if isExpanded}
                    <!-- Direct permissions -->
                    {#if catPerms.length > 0}
                      <div class="edit-cat-perms">
                        {#each catPerms as perm (perm.node)}
                          {@const sel = editSelectedPermissions.includes(
                            perm.node
                          )}
                          {@const hasFields =
                            perm.fieldLevelPermissions &&
                            perm.fieldLevelPermissions.length > 0}
                          {@const fieldsExpanded =
                            hasFields &&
                            expandedCategories.has(`field:${perm.node}`)}
                          <label
                            class="edit-perm-row"
                            class:edit-perm-sel={sel}
                          >
                            <input
                              type="checkbox"
                              checked={sel}
                              on:change={() => toggleEditPermission(perm.node)}
                            />
                            <div class="edit-perm-info">
                              <span class="edit-perm-node">{perm.node}</span>
                              {#if perm.description}
                                <span class="edit-perm-desc"
                                  >{perm.description}</span
                                >
                              {/if}
                            </div>
                            {#if hasFields}
                              <button
                                type="button"
                                class="edit-field-expand-btn"
                                on:click|preventDefault|stopPropagation={() =>
                                  toggleCategory(`field:${perm.node}`)}
                                title={fieldsExpanded
                                  ? "Hide field permissions"
                                  : `Show ${perm.fieldLevelPermissions?.length} field permissions`}
                              >
                                <svg
                                  class="chevron"
                                  class:rotated={fieldsExpanded}
                                  viewBox="0 0 24 24"
                                  fill="none"
                                  stroke="currentColor"
                                  stroke-width="2.5"
                                  width="9"
                                  height="9"
                                >
                                  <polyline points="9 18 15 12 9 6" />
                                </svg>
                                <span class="edit-field-expand-count"
                                  >{perm.fieldLevelPermissions?.length}</span
                                >
                              </button>
                            {/if}
                          </label>
                          {#if hasFields && fieldsExpanded}
                            {@const fieldAllSel =
                              perm.fieldLevelPermissions?.every((f) =>
                                editSelectedPermissions.includes(f)
                              ) ?? false}
                            {@const fieldSomeSel =
                              !fieldAllSel &&
                              (perm.fieldLevelPermissions?.some((f) =>
                                editSelectedPermissions.includes(f)
                              ) ??
                                false)}
                            <div class="edit-field-perms-wrap">
                              <div class="edit-field-perms-header">
                                <span class="edit-field-perms-label"
                                  >Field Permissions</span
                                >
                                <button
                                  type="button"
                                  class="edit-cat-all-btn"
                                  on:click={() =>
                                    toggleFieldLevelPerms(
                                      perm.fieldLevelPermissions ?? []
                                    )}
                                >
                                  <div
                                    class="edit-cb"
                                    class:edit-cb-checked={fieldAllSel}
                                    class:edit-cb-indeterminate={fieldSomeSel}
                                  >
                                    {#if fieldAllSel}
                                      <svg
                                        viewBox="0 0 10 10"
                                        fill="none"
                                        stroke="currentColor"
                                        stroke-width="2"
                                        width="8"
                                        height="8"
                                      >
                                        <polyline points="1.5 5 4 8 8.5 2" />
                                      </svg>
                                    {:else if fieldSomeSel}
                                      <svg
                                        viewBox="0 0 10 10"
                                        fill="none"
                                        stroke="currentColor"
                                        stroke-width="2.5"
                                        width="8"
                                        height="8"
                                      >
                                        <line x1="1.5" y1="5" x2="8.5" y2="5" />
                                      </svg>
                                    {/if}
                                  </div>
                                  All
                                </button>
                              </div>
                              {#each perm.fieldLevelPermissions ?? [] as fieldPerm (fieldPerm)}
                                {@const fSel =
                                  editSelectedPermissions.includes(fieldPerm)}
                                <label
                                  class="edit-perm-row edit-field-perm-row"
                                  class:edit-perm-sel={fSel}
                                >
                                  <input
                                    type="checkbox"
                                    checked={fSel}
                                    on:change={() =>
                                      toggleEditPermission(fieldPerm)}
                                  />
                                  <span
                                    class="edit-perm-node edit-field-perm-node"
                                    >{fieldPerm}</span
                                  >
                                </label>
                              {/each}
                            </div>
                          {/if}
                        {/each}
                      </div>
                    {/if}

                    <!-- Subcategories -->
                    {#if hasSubCats}
                      <div
                        class="edit-sub-cat-list"
                        class:edit-sub-cat-list-no-direct={catPerms.length ===
                          0}
                      >
                        {#each Object.entries(category.subCategories ?? {}) as [subKey, subCat] (subKey)}
                          {@const subCategory = subCat}
                          {@const subPerms = subCategory.permissions ?? []}
                          {@const subAllNodes =
                            collectAllPermNodes(subCategory)}
                          {@const subAllSelectables =
                            allSelectableStrings(subAllNodes)}
                          {@const subAllSel =
                            subAllSelectables.length > 0 &&
                            subAllSelectables.every((s) =>
                              editSelectedPermissions.includes(s)
                            )}
                          {@const subSomeSel =
                            !subAllSel &&
                            subAllSelectables.some((s) =>
                              editSelectedPermissions.includes(s)
                            )}
                          {@const subExpanded = expandedCategories.has(
                            `${catKey}/${subKey}`
                          )}
                          <div class="edit-sub-cat-group">
                            <div class="edit-sub-cat-header">
                              <button
                                type="button"
                                class="edit-sub-cat-toggle"
                                on:click={() =>
                                  toggleCategory(`${catKey}/${subKey}`)}
                                aria-expanded={subExpanded}
                              >
                                <svg
                                  class="chevron"
                                  class:rotated={subExpanded}
                                  viewBox="0 0 24 24"
                                  fill="none"
                                  stroke="currentColor"
                                  stroke-width="2.5"
                                  width="9"
                                  height="9"
                                >
                                  <polyline points="9 18 15 12 9 6" />
                                </svg>
                                <span class="edit-sub-cat-name"
                                  >{subCategory.name}</span
                                >
                                <span class="edit-cat-count"
                                  >{subAllSelectables.length}</span
                                >
                              </button>
                              <button
                                type="button"
                                class="edit-cat-all-btn"
                                on:click={() =>
                                  toggleAllInCategory(subAllNodes)}
                                title={subAllSel
                                  ? "Deselect all"
                                  : "Select all"}
                              >
                                <div
                                  class="edit-cb"
                                  class:edit-cb-checked={subAllSel}
                                  class:edit-cb-indeterminate={subSomeSel}
                                >
                                  {#if subAllSel}
                                    <svg
                                      viewBox="0 0 10 10"
                                      fill="none"
                                      stroke="currentColor"
                                      stroke-width="2"
                                      width="8"
                                      height="8"
                                    >
                                      <polyline points="1.5 5 4 8 8.5 2" />
                                    </svg>
                                  {:else if subSomeSel}
                                    <svg
                                      viewBox="0 0 10 10"
                                      fill="none"
                                      stroke="currentColor"
                                      stroke-width="2.5"
                                      width="8"
                                      height="8"
                                    >
                                      <line x1="1.5" y1="5" x2="8.5" y2="5" />
                                    </svg>
                                  {/if}
                                </div>
                                All
                              </button>
                            </div>

                            {#if subExpanded}
                              <div class="edit-cat-perms edit-sub-cat-perms">
                                {#each subPerms as perm (perm.node)}
                                  {@const sel =
                                    editSelectedPermissions.includes(perm.node)}
                                  {@const hasFields =
                                    perm.fieldLevelPermissions &&
                                    perm.fieldLevelPermissions.length > 0}
                                  {@const fieldsExpanded =
                                    hasFields &&
                                    expandedCategories.has(
                                      `field:${perm.node}`
                                    )}
                                  <label
                                    class="edit-perm-row"
                                    class:edit-perm-sel={sel}
                                  >
                                    <input
                                      type="checkbox"
                                      checked={sel}
                                      on:change={() =>
                                        toggleEditPermission(perm.node)}
                                    />
                                    <div class="edit-perm-info">
                                      <span class="edit-perm-node"
                                        >{perm.node}</span
                                      >
                                      {#if perm.description}
                                        <span class="edit-perm-desc"
                                          >{perm.description}</span
                                        >
                                      {/if}
                                    </div>
                                    {#if hasFields}
                                      <button
                                        type="button"
                                        class="edit-field-expand-btn"
                                        on:click|preventDefault|stopPropagation={() =>
                                          toggleCategory(`field:${perm.node}`)}
                                        title={fieldsExpanded
                                          ? "Hide field permissions"
                                          : `Show ${perm.fieldLevelPermissions?.length} field permissions`}
                                      >
                                        <svg
                                          class="chevron"
                                          class:rotated={fieldsExpanded}
                                          viewBox="0 0 24 24"
                                          fill="none"
                                          stroke="currentColor"
                                          stroke-width="2.5"
                                          width="9"
                                          height="9"
                                        >
                                          <polyline points="9 18 15 12 9 6" />
                                        </svg>
                                        <span class="edit-field-expand-count"
                                          >{perm.fieldLevelPermissions
                                            ?.length}</span
                                        >
                                      </button>
                                    {/if}
                                  </label>
                                  {#if hasFields && fieldsExpanded}
                                    {@const fieldAllSel =
                                      perm.fieldLevelPermissions?.every((f) =>
                                        editSelectedPermissions.includes(f)
                                      ) ?? false}
                                    {@const fieldSomeSel =
                                      !fieldAllSel &&
                                      (perm.fieldLevelPermissions?.some((f) =>
                                        editSelectedPermissions.includes(f)
                                      ) ??
                                        false)}
                                    <div class="edit-field-perms-wrap">
                                      <div class="edit-field-perms-header">
                                        <span class="edit-field-perms-label"
                                          >Field Permissions</span
                                        >
                                        <button
                                          type="button"
                                          class="edit-cat-all-btn"
                                          on:click={() =>
                                            toggleFieldLevelPerms(
                                              perm.fieldLevelPermissions ?? []
                                            )}
                                        >
                                          <div
                                            class="edit-cb"
                                            class:edit-cb-checked={fieldAllSel}
                                            class:edit-cb-indeterminate={fieldSomeSel}
                                          >
                                            {#if fieldAllSel}
                                              <svg
                                                viewBox="0 0 10 10"
                                                fill="none"
                                                stroke="currentColor"
                                                stroke-width="2"
                                                width="8"
                                                height="8"
                                              >
                                                <polyline
                                                  points="1.5 5 4 8 8.5 2"
                                                />
                                              </svg>
                                            {:else if fieldSomeSel}
                                              <svg
                                                viewBox="0 0 10 10"
                                                fill="none"
                                                stroke="currentColor"
                                                stroke-width="2.5"
                                                width="8"
                                                height="8"
                                              >
                                                <line
                                                  x1="1.5"
                                                  y1="5"
                                                  x2="8.5"
                                                  y2="5"
                                                />
                                              </svg>
                                            {/if}
                                          </div>
                                          All
                                        </button>
                                      </div>
                                      {#each perm.fieldLevelPermissions ?? [] as fieldPerm (fieldPerm)}
                                        {@const fSel =
                                          editSelectedPermissions.includes(
                                            fieldPerm
                                          )}
                                        <label
                                          class="edit-perm-row edit-field-perm-row"
                                          class:edit-perm-sel={fSel}
                                        >
                                          <input
                                            type="checkbox"
                                            checked={fSel}
                                            on:change={() =>
                                              toggleEditPermission(fieldPerm)}
                                          />
                                          <span
                                            class="edit-perm-node edit-field-perm-node"
                                            >{fieldPerm}</span
                                          >
                                        </label>
                                      {/each}
                                    </div>
                                  {/if}
                                {/each}
                              </div>
                            {/if}
                          </div>
                        {/each}
                      </div>
                    {/if}
                  {/if}
                </div>
              {/each}
            {/if}

            <!-- Custom permission nodes -->
            {#if customNodes.length > 0}
              <div class="edit-cat-group">
                <div class="edit-cat-header">
                  <div class="edit-cat-toggle edit-custom-cat-label">
                    <svg
                      viewBox="0 0 24 24"
                      fill="none"
                      stroke="currentColor"
                      stroke-width="2"
                      width="10"
                      height="10"
                    >
                      <line x1="12" y1="5" x2="12" y2="19" />
                      <line x1="5" y1="12" x2="19" y2="12" />
                    </svg>
                    <span class="edit-cat-name">Custom</span>
                    <span class="edit-cat-count">{customNodes.length}</span>
                  </div>
                </div>
                <div class="edit-cat-perms">
                  {#each customNodes as node (node)}
                    {@const sel = editSelectedPermissions.includes(node)}
                    <label class="edit-perm-row" class:edit-perm-sel={sel}>
                      <input
                        type="checkbox"
                        checked={sel}
                        on:change={() => toggleEditPermission(node)}
                      />
                      <span class="edit-perm-node">{node}</span>
                    </label>
                  {/each}
                </div>
              </div>
            {/if}
          </div>
        </div>
      {/if}

      <div class="confirm-actions">
        <button
          type="button"
          class="btn-cancel"
          on:click={onClose}
          disabled={isEditing}
        >
          Cancel
        </button>
        <button
          type="submit"
          class="btn-save"
          disabled={isEditing || !editName.trim()}
        >
          {isEditing ? "Saving…" : "Save Changes"}
        </button>
      </div>
    </form>
  </div>
</div>

<style>
  /* ── Backdrop & dialog ── */
  .confirm-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
  }

  .edit-dialog {
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    border-radius: 12px;
    box-shadow: 0 20px 40px rgba(0, 0, 0, 0.25);
    width: 90%;
    max-width: 520px;
    max-height: 85vh;
    overflow-y: auto;
    padding: 28px 24px 22px;
    animation: modalIn 0.15s ease;
  }

  @keyframes modalIn {
    from {
      opacity: 0;
      transform: translateY(8px) scale(0.97);
    }
    to {
      opacity: 1;
      transform: translateY(0) scale(1);
    }
  }

  .edit-dialog-title {
    margin: 0 0 4px;
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
  }

  .edit-dialog-sub {
    margin: 0 0 18px;
    font-size: 13px;
    color: var(--text-secondary);
  }

  .confirm-error {
    margin: 0 0 12px;
    font-size: 13px;
    color: #dc2626;
  }

  /* ── Form fields ── */
  .edit-field {
    display: flex;
    flex-direction: column;
    gap: 5px;
    margin-bottom: 14px;
  }

  .edit-field label {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }

  .edit-field input {
    padding: 8px 12px;
    border: 1px solid var(--border-subtle);
    border-radius: 7px;
    background: var(--bg-inset);
    font-size: 13px;
    color: var(--text-primary);
    transition:
      border-color 0.15s,
      box-shadow 0.15s;
  }

  .edit-field input:focus {
    outline: none;
    border-color: var(--input-focus-border);
    box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
  }

  /* ── Actions ── */
  .confirm-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    justify-content: center;
  }

  .btn-cancel {
    padding: 7px 16px;
    border-radius: 7px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    background: var(--bg-inset);
    border: 1px solid var(--border-subtle);
    color: var(--text-secondary);
    transition:
      background 0.15s,
      border-color 0.15s;
  }

  .btn-cancel:hover:not(:disabled) {
    background: var(--card-hover-bg);
    border-color: var(--border-default);
    color: var(--text-primary);
  }

  .btn-cancel:disabled {
    opacity: 0.45;
    cursor: not-allowed;
  }

  .btn-save {
    padding: 7px 16px;
    border-radius: 7px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    background: var(--accent-color, #0066cc);
    border: 1px solid transparent;
    color: #fff;
    transition: filter 0.15s;
  }

  .btn-save:hover:not(:disabled) {
    filter: brightness(1.1);
  }

  .btn-save:disabled {
    opacity: 0.45;
    cursor: not-allowed;
  }

  /* ── Edit sections (roles & permissions) ── */
  .edit-section {
    margin-bottom: 16px;
    border-top: 1px solid var(--border-subtle);
    padding-top: 14px;
  }

  .edit-section-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 10px;
  }

  .edit-section-label svg {
    color: var(--text-muted);
    flex-shrink: 0;
  }

  .edit-section-count {
    font-size: 11px;
    font-weight: 500;
    color: var(--text-muted);
    text-transform: none;
    letter-spacing: normal;
    margin-left: auto;
  }

  /* ── Role chips ── */
  .edit-role-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 160px;
    overflow-y: auto;
    padding-right: 4px;
  }

  .edit-role-chip {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    background: var(--bg-inset);
    border: 1px solid var(--border-subtle);
    border-radius: 6px;
    cursor: pointer;
    font-size: 13px;
    color: var(--text-primary);
    text-align: left;
    transition:
      background 0.12s,
      border-color 0.12s;
  }

  .edit-role-chip:hover {
    background: var(--card-hover-bg);
  }

  .edit-role-chip.selected {
    background: rgba(0, 102, 204, 0.08);
    border-color: var(--accent-color, #0066cc);
  }

  .edit-role-check {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    border-radius: 4px;
    border: 1.5px solid var(--border-subtle);
    flex-shrink: 0;
    color: var(--accent-color, #0066cc);
    transition: border-color 0.12s;
  }

  .edit-role-chip.selected .edit-role-check {
    border-color: var(--accent-color, #0066cc);
    background: var(--accent-color, #0066cc);
    color: #fff;
  }

  .edit-role-chip-title {
    font-weight: 600;
    font-size: 13px;
  }

  .edit-role-chip-moniker {
    font-family: ui-monospace, "SF Mono", "Cascadia Code", Menlo, monospace;
    font-size: 11px;
    color: var(--text-muted);
    margin-left: auto;
  }

  /* ── Custom permission input ── */
  .edit-custom-perm-wrap {
    display: flex;
    gap: 6px;
    margin-bottom: 8px;
  }

  .edit-custom-perm-input {
    flex: 1;
    padding: 6px 10px;
    border: 1px solid var(--border-subtle);
    border-radius: 6px;
    background: var(--bg-inset);
    font-family: ui-monospace, "SF Mono", "Cascadia Code", Menlo, monospace;
    font-size: 12px;
    color: var(--text-primary);
    transition:
      border-color 0.15s,
      box-shadow 0.15s;
  }

  .edit-custom-perm-input::placeholder {
    color: var(--text-muted);
    font-family: inherit;
  }

  .edit-custom-perm-input:focus {
    outline: none;
    border-color: var(--input-focus-border);
    box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1);
  }

  .edit-custom-perm-btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 6px 12px;
    background: var(--accent-color, #0066cc);
    color: #fff;
    border: none;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 500;
    cursor: pointer;
    white-space: nowrap;
    transition: filter 0.15s;
  }

  .edit-custom-perm-btn:hover:not(:disabled) {
    filter: brightness(1.1);
  }

  .edit-custom-perm-btn:disabled {
    opacity: 0.45;
    cursor: not-allowed;
  }

  .edit-custom-perm-error {
    margin: 0 0 6px;
    font-size: 11.5px;
    color: #dc2626;
  }

  /* ── Categorized permission list ── */
  .edit-perm-list {
    border: 1px solid var(--border-subtle);
    border-radius: 6px;
    overflow-y: auto;
    max-height: 260px;
    background: var(--bg-inset);
  }

  .edit-perm-empty {
    margin: 0;
    padding: 12px;
    font-size: 12.5px;
    color: var(--text-muted);
    text-align: center;
  }

  /* ── Category groups ── */
  .edit-cat-group {
    border-bottom: 1px solid var(--border-subtle);
  }

  .edit-cat-group:last-child {
    border-bottom: none;
  }

  .edit-cat-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-right: 8px;
  }

  .edit-cat-toggle {
    display: flex;
    align-items: center;
    gap: 5px;
    flex: 1;
    padding: 6px 8px;
    background: none;
    border: none;
    cursor: pointer;
    text-align: left;
    transition: background 0.1s;
  }

  .edit-cat-toggle:hover {
    background: var(--card-hover-bg);
  }

  .edit-custom-cat-label {
    cursor: default;
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 6px 8px;
  }

  .edit-custom-cat-label svg {
    color: var(--text-muted);
    flex-shrink: 0;
  }

  .chevron {
    color: var(--text-muted);
    flex-shrink: 0;
    transition: transform 0.15s ease;
  }

  .chevron.rotated {
    transform: rotate(90deg);
  }

  .edit-cat-name {
    font-size: 11.5px;
    font-weight: 600;
    color: var(--text-primary);
  }

  .edit-cat-count {
    font-size: 10px;
    color: var(--text-muted);
    background: var(--bg-surface);
    border: 1px solid var(--border-subtle);
    padding: 0 5px;
    border-radius: 7px;
  }

  .edit-cat-all-btn {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 2px 6px;
    background: none;
    border: 1px solid var(--border-subtle);
    border-radius: 4px;
    cursor: pointer;
    font-size: 10px;
    font-weight: 500;
    color: var(--text-secondary);
    flex-shrink: 0;
    transition:
      background 0.1s,
      border-color 0.1s;
  }

  .edit-cat-all-btn:hover {
    background: var(--card-hover-bg);
    border-color: var(--border-default);
  }

  /* ── Custom checkbox ── */
  .edit-cb {
    width: 12px;
    height: 12px;
    border: 1.5px solid var(--border-default);
    border-radius: 3px;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    background: var(--bg-surface);
    color: #fff;
    transition:
      background 0.1s,
      border-color 0.1s;
  }

  .edit-cb.edit-cb-checked {
    background: var(--accent-color, #0066cc);
    border-color: var(--accent-color, #0066cc);
  }

  .edit-cb.edit-cb-indeterminate {
    background: var(--bg-surface);
    border-color: var(--accent-color, #0066cc);
    color: var(--accent-color, #0066cc);
  }

  /* ── Permission rows ── */
  .edit-cat-perms {
    padding: 2px 0 4px;
    border-top: 1px solid var(--border-subtle);
  }

  .edit-perm-row {
    display: flex;
    align-items: flex-start;
    gap: 7px;
    padding: 4px 8px 4px 20px;
    cursor: pointer;
    transition: background 0.1s;
  }

  .edit-perm-row:hover {
    background: var(--card-hover-bg);
  }

  .edit-perm-row.edit-perm-sel {
    background: rgba(0, 102, 204, 0.05);
  }

  .edit-perm-row input[type="checkbox"] {
    accent-color: var(--accent-color, #0066cc);
    width: 13px;
    height: 13px;
    flex-shrink: 0;
    cursor: pointer;
    margin-top: 1px;
  }

  .edit-perm-info {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
  }

  .edit-perm-node {
    font-family: ui-monospace, "SF Mono", "Cascadia Code", Menlo, monospace;
    font-size: 11px;
    font-weight: 500;
    color: var(--text-primary);
  }

  .edit-perm-desc {
    font-size: 10px;
    color: var(--text-muted);
    line-height: 1.3;
  }

  /* ── Subcategories ── */
  .edit-sub-cat-list {
    border-top: 1px solid var(--border-subtle);
  }

  .edit-sub-cat-list-no-direct {
    border-top: 1px solid var(--border-subtle);
  }

  .edit-sub-cat-group {
    border-bottom: 1px solid var(--border-subtle);
  }

  .edit-sub-cat-group:last-child {
    border-bottom: none;
  }

  .edit-sub-cat-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-right: 8px;
  }

  .edit-sub-cat-toggle {
    display: flex;
    align-items: center;
    gap: 5px;
    flex: 1;
    padding: 5px 8px 5px 18px;
    background: none;
    border: none;
    cursor: pointer;
    text-align: left;
    transition: background 0.1s;
  }

  .edit-sub-cat-toggle:hover {
    background: var(--card-hover-bg);
  }

  .edit-sub-cat-name {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
  }

  .edit-sub-cat-perms {
    padding-left: 10px;
  }

  /* ── Field-level permissions ── */
  .edit-field-expand-btn {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-left: auto;
    padding: 1px 5px;
    background: none;
    border: 1px solid var(--border-subtle);
    border-radius: 4px;
    cursor: pointer;
    flex-shrink: 0;
    transition:
      background 0.1s,
      border-color 0.1s;
  }

  .edit-field-expand-btn:hover {
    background: var(--card-hover-bg);
    border-color: var(--border-default);
  }

  .edit-field-expand-count {
    font-size: 9.5px;
    font-weight: 500;
    color: var(--text-muted);
    white-space: nowrap;
  }

  .edit-field-perms-wrap {
    margin: 0 0 4px;
    padding: 3px 0 3px 32px;
    border-left: 2px solid var(--border-subtle);
    margin-left: 26px;
  }

  .edit-field-perms-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 2px 6px 3px 4px;
  }

  .edit-field-perms-label {
    font-size: 9.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
  }

  .edit-field-perm-row {
    padding: 2px 6px 2px 4px;
  }

  .edit-field-perm-node {
    font-size: 10px;
    color: var(--text-secondary);
  }

  /* Scrollbars */
  .edit-role-list::-webkit-scrollbar,
  .edit-perm-list::-webkit-scrollbar {
    width: 5px;
  }

  .edit-role-list::-webkit-scrollbar-track,
  .edit-perm-list::-webkit-scrollbar-track {
    background: transparent;
  }

  .edit-role-list::-webkit-scrollbar-thumb,
  .edit-perm-list::-webkit-scrollbar-thumb {
    background: var(--scrollbar-thumb);
    border-radius: 3px;
  }
</style>
