<script lang="ts">
  import { onMount } from 'svelte';
  import { api } from '$lib/api';
  import { toast } from '$lib/toast';
  import type {
    InternalRole,
    InternalRoleCreateInput,
    InternalRoleModuleDefinition,
    InternalRoleUpdateInput
  } from '$lib/types';
  import { Pencil, ShieldCheck, Trash2, TriangleAlert, Waypoints, Plus } from 'lucide-svelte';

  let roles = $state<InternalRole[]>([]);
  let modules = $state<InternalRoleModuleDefinition[]>([]);
  let loading = $state(true);
  let loadError = $state('');

  async function load() {
    loading = true;
    loadError = '';
    try {
      const [roleList, moduleList] = await Promise.all([
        api.accessRoles(),
        api.accessRoleModules()
      ]);
      roles = roleList;
      modules = moduleList;
    } catch (err: unknown) {
      loadError = err instanceof Error ? err.message : 'Failed to load roles';
    } finally {
      loading = false;
    }
  }

  onMount(load);

  function emptyModulePermissions() {
    return Object.fromEntries(modules.map((module) => [module.key, 'none'])) as Record<string, string>;
  }

  type FormMode = 'create' | 'edit';
  let formOpen = $state(false);
  let formMode = $state<FormMode>('create');
  let formRoleId = $state<number | null>(null);
  let formName = $state('');
  let formDescription = $state('');
  let formModulePermissions = $state<Record<string, string>>({});
  let formProtected = $state(false);
  let formSaving = $state(false);
  let formError = $state('');

  function openCreate() {
    formMode = 'create';
    formRoleId = null;
    formName = '';
    formDescription = '';
    formModulePermissions = emptyModulePermissions();
    formProtected = false;
    formError = '';
    formOpen = true;
  }

  function openEdit(role: InternalRole) {
    formMode = 'edit';
    formRoleId = role.id;
    formName = role.name;
    formDescription = role.description ?? '';
    formModulePermissions = { ...emptyModulePermissions(), ...role.module_permissions };
    formProtected = role.is_protected;
    formError = '';
    formOpen = true;
  }

  function closeForm() {
    if (formSaving) return;
    formOpen = false;
  }

  function setModuleLevel(moduleKey: string, level: string) {
    formModulePermissions = { ...formModulePermissions, [moduleKey]: level };
  }

  function summary(role: InternalRole) {
    return modules
      .map((module) => {
        const level = role.module_permissions[module.key];
        return level && level !== 'none' ? `${module.label}: ${level}` : null;
      })
      .filter(Boolean)
      .join(' • ');
  }

  async function saveForm() {
    formError = '';
    const name = formName.trim();
    if (!name) {
      formError = 'Role name is required';
      return;
    }

    formSaving = true;
    const tid = toast.loading(formMode === 'create' ? 'Creating role…' : 'Saving role…');
    try {
      const payload: InternalRoleCreateInput | InternalRoleUpdateInput = {
        name,
        description: formDescription.trim() || null,
        module_permissions: formModulePermissions
      };

      if (formMode === 'create') {
        await api.createAccessRole(payload as InternalRoleCreateInput);
      } else if (formRoleId != null) {
        await api.updateAccessRole(formRoleId, payload);
      }

      toast.dismiss(tid);
      toast.success(formMode === 'create' ? 'Role created' : 'Role updated');
      formOpen = false;
      await load();
    } catch (err: unknown) {
      toast.dismiss(tid);
      const message = err instanceof Error ? err.message : 'An error occurred';
      formError = message;
      toast.error(message);
    } finally {
      formSaving = false;
    }
  }

  let deleteRole = $state<InternalRole | null>(null);
  let deleting = $state(false);

  function openDelete(role: InternalRole) {
    deleteRole = role;
  }

  function closeDelete() {
    if (deleting) return;
    deleteRole = null;
  }

  async function confirmDelete() {
    if (!deleteRole) return;
    deleting = true;
    const tid = toast.loading('Deleting role…');
    try {
      await api.deleteAccessRole(deleteRole.id);
      toast.dismiss(tid);
      toast.success(`Deleted ${deleteRole.name}`);
      deleteRole = null;
      await load();
    } catch (err: unknown) {
      toast.dismiss(tid);
      toast.error(err instanceof Error ? err.message : 'Failed to delete role');
    } finally {
      deleting = false;
    }
  }
</script>

<div class="panel-section">
  <header class="panel-header">
    <div class="header-copy">
      <h2>Roles</h2>
      <p>Define which modules each role can open, edit, or manage.</p>
    </div>
    <button type="button" class="btn-primary" onclick={openCreate}>
      <Plus size={16} strokeWidth={2.2} /> Add role
    </button>
  </header>

  {#if loading}
    <p class="state-msg">Loading roles…</p>
  {:else if loadError}
    <p class="state-msg error"><TriangleAlert size={15} strokeWidth={2.2} /> {loadError}</p>
  {:else}
    <div class="table-wrap">
      <table class="roles-table">
        <thead>
          <tr>
            <th>Role</th>
            <th>Assigned users</th>
            <th>Module access</th>
            <th class="actions-col">Actions</th>
          </tr>
        </thead>
        <tbody>
          {#each roles as role (role.id)}
            <tr>
              <td>
                <div class="role-cell">
                  <div class="role-title-row">
                    <strong>{role.name}</strong>
                    {#if role.is_protected}
                      <span class="protected-chip">
                        <ShieldCheck size={12} strokeWidth={2.4} /> Protected
                      </span>
                    {/if}
                  </div>
                  {#if role.description}
                    <p>{role.description}</p>
                  {/if}
                </div>
              </td>
              <td>{role.user_count}</td>
              <td class="summary-cell">{summary(role) || 'No module access'}</td>
              <td class="actions-col">
                <div class="row-actions">
                  <button type="button" class="icon-btn" title="Edit role" onclick={() => openEdit(role)}>
                    <Pencil size={15} strokeWidth={2.1} />
                  </button>
                  <button
                    type="button"
                    class="icon-btn danger"
                    title={role.is_protected
                      ? 'Lean and admin roles cannot be deleted'
                      : role.user_count > 0
                        ? 'Reassign users before deleting this role'
                        : 'Delete role'}
                    disabled={role.is_protected || role.user_count > 0}
                    onclick={() => openDelete(role)}
                  >
                    <Trash2 size={15} strokeWidth={2.1} />
                  </button>
                </div>
              </td>
            </tr>
          {/each}
        </tbody>
      </table>
    </div>
  {/if}
</div>

{#if formOpen}
  <div class="modal-backdrop" role="presentation" onclick={closeForm}>
    <div
      class="modal-card modal-card-wide"
      role="dialog"
      aria-modal="true"
      aria-labelledby="role-form-title"
      tabindex="-1"
      onclick={(event) => event.stopPropagation()}
      onkeydown={(event) => { if (event.key === 'Escape') closeForm(); }}
    >
      <div class="modal-top">
        <div class="modal-icon"><Waypoints size={20} strokeWidth={2.2} /></div>
        <div>
          <h2 id="role-form-title" class="modal-title">{formMode === 'create' ? 'Add role' : 'Edit role'}</h2>
          <p class="modal-text">Module access levels are translated into the underlying permissions automatically.</p>
        </div>
      </div>

      <form class="modal-form" onsubmit={(event) => { event.preventDefault(); saveForm(); }}>
        <div class="field-row">
          <div class="field">
            <label for="rf-name">Role name</label>
            <input id="rf-name" type="text" bind:value={formName} disabled={formProtected && formMode === 'edit'} required />
          </div>
          <div class="field">
            <label for="rf-description">Description</label>
            <input id="rf-description" type="text" bind:value={formDescription} />
          </div>
        </div>

        <div class="permissions-section">
          <div class="permissions-head">
            <div>
              <h3>Module access</h3>
              <p>Each row controls where this role can go and what it can do there.</p>
            </div>
          </div>

          <div class="permissions-scroll">
            <table class="permissions-table">
              <thead>
                <tr>
                  <th>Module</th>
                  <th>What it covers</th>
                  <th>Access level</th>
                </tr>
              </thead>
              <tbody>
                {#each modules as module (module.key)}
                  <tr>
                    <td class="module-name-cell">
                      <strong>{module.label}</strong>
                    </td>
                    <td class="module-description-cell">{module.description}</td>
                    <td class="module-level-cell">
                      <label class="matrix-select">
                        <span class="sr-only">Access level for {module.label}</span>
                        <select
                          value={formModulePermissions[module.key] ?? 'none'}
                          onchange={(event) => setModuleLevel(module.key, (event.currentTarget as HTMLSelectElement).value)}
                        >
                          {#each module.levels as level (level)}
                            <option value={level}>{level}</option>
                          {/each}
                        </select>
                      </label>
                    </td>
                  </tr>
                {/each}
              </tbody>
            </table>
          </div>
        </div>

        {#if formError}
          <p class="form-error"><TriangleAlert size={15} strokeWidth={2.2} /> {formError}</p>
        {/if}

        <div class="modal-actions">
          <button type="button" class="modal-cancel" onclick={closeForm} disabled={formSaving}>Cancel</button>
          <button type="submit" class="btn-primary" disabled={formSaving}>
            {formSaving ? 'Saving…' : formMode === 'create' ? 'Create role' : 'Save changes'}
          </button>
        </div>
      </form>
    </div>
  </div>
{/if}

{#if deleteRole}
  <div class="modal-backdrop" role="presentation" onclick={closeDelete}>
    <div
      class="modal-card"
      role="dialog"
      aria-modal="true"
      aria-labelledby="delete-role-title"
      tabindex="-1"
      onclick={(event) => event.stopPropagation()}
      onkeydown={(event) => { if (event.key === 'Escape') closeDelete(); }}
    >
      <div class="modal-icon danger"><Trash2 size={20} strokeWidth={2.2} /></div>
      <h2 id="delete-role-title" class="modal-title">Delete role?</h2>
      <p class="modal-text">
        This removes <strong>{deleteRole.name}</strong>. Users must be reassigned first.
      </p>
      <div class="modal-actions">
        <button type="button" class="modal-cancel" onclick={closeDelete} disabled={deleting}>Cancel</button>
        <button type="button" class="modal-confirm" onclick={confirmDelete} disabled={deleting}>
          {deleting ? 'Deleting…' : 'Delete role'}
        </button>
      </div>
    </div>
  </div>
{/if}

<style>
  .panel-section {
    display: flex;
    flex-direction: column;
  }

  .panel-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.5rem 1.75rem 1.25rem;
    border-bottom: 1px solid var(--line);
  }

  .header-copy h2,
  .modal-title {
    margin: 0;
    font-size: 1.1rem;
    font-weight: 700;
  }

  .header-copy p,
  .modal-text {
    margin: 0.3rem 0 0;
    font-size: 0.85rem;
    color: var(--muted);
  }

  .btn-primary,
  .modal-confirm,
  .modal-cancel,
  .icon-btn {
    transition: opacity 140ms ease, border-color 140ms ease, color 140ms ease, background-color 140ms ease;
  }

  .btn-primary {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.55rem 1.1rem;
    background: var(--color-brand);
    color: #fff;
    border: none;
    border-radius: 0.6rem;
    font-size: 0.86rem;
    font-weight: 600;
    cursor: pointer;
  }

  .btn-primary:disabled,
  .modal-confirm:disabled,
  .modal-cancel:disabled,
  .icon-btn:disabled {
    opacity: 0.55;
    cursor: not-allowed;
  }

  .state-msg {
    padding: 1.5rem 1.75rem;
    margin: 0;
    color: var(--muted);
  }

  .state-msg.error,
  .form-error {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    color: #c53030;
  }

  .table-wrap {
    overflow-x: auto;
    padding: 0.5rem 1.75rem 1.75rem;
  }

  .roles-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.88rem;
  }

  .roles-table th,
  .roles-table td {
    padding: 0.75rem;
    border-bottom: 1px solid var(--line);
    text-align: left;
    vertical-align: top;
  }

  .roles-table th {
    font-size: 0.74rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--muted);
  }

  .role-cell p,
  .summary-cell {
    margin: 0.25rem 0 0;
    color: var(--muted);
    line-height: 1.45;
  }

  .role-title-row {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    flex-wrap: wrap;
  }

  .protected-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    padding: 0.08rem 0.42rem;
    border-radius: 0.5rem;
    background: color-mix(in srgb, var(--color-brand) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-brand) 30%, transparent);
    color: var(--color-brand);
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
  }

  .actions-col {
    text-align: right;
    white-space: nowrap;
  }

  .row-actions {
    display: inline-flex;
    gap: 0.3rem;
  }

  .icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border: 1px solid var(--line);
    border-radius: 0.55rem;
    background: var(--panel);
    color: var(--muted);
    cursor: pointer;
  }

  .icon-btn:hover:not(:disabled) {
    color: var(--text);
    border-color: var(--color-brand);
  }

  .icon-btn.danger:hover:not(:disabled) {
    color: #c53030;
    border-color: color-mix(in srgb, #e53e3e 45%, transparent);
  }

  .modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 80;
    display: grid;
    place-items: center;
    padding: 1.5rem;
    background: color-mix(in srgb, var(--color-text-primary, #000) 32%, transparent);
    backdrop-filter: blur(6px);
  }

  .modal-card {
    width: min(34rem, 100%);
    display: grid;
    gap: 0.8rem;
    padding: 1.6rem;
    border: 1px solid var(--line);
    border-radius: 1rem;
    background: var(--panel);
    box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.45);
  }

  .modal-card-wide {
    width: min(54rem, 100%);
    max-height: min(88vh, 60rem);
  }

  .modal-top {
    display: flex;
    gap: 0.85rem;
    align-items: flex-start;
  }

  .modal-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.6rem;
    height: 2.6rem;
    border-radius: 0.8rem;
    background: color-mix(in srgb, var(--color-brand) 12%, transparent);
    color: var(--color-brand);
  }

  .modal-icon.danger {
    background: #fdecee;
    color: #b3261e;
  }

  .modal-form {
    display: grid;
    gap: 0.85rem;
    min-height: 0;
  }

  .field-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.9rem;
  }

  .field,
  .matrix-select {
    display: grid;
    gap: 0.4rem;
  }

  .field label,
  .matrix-select span {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--text);
  }

  .field input,
  .matrix-select select {
    width: 100%;
    padding: 0.58rem 0.8rem;
    border: 1px solid var(--line);
    border-radius: 0.55rem;
    background: var(--panel-soft);
    color: var(--text);
    font-size: 0.9rem;
    box-sizing: border-box;
  }

  .permissions-section {
    display: grid;
    gap: 0.75rem;
    min-height: 0;
  }

  .permissions-head h3 {
    margin: 0;
    font-size: 0.94rem;
    font-weight: 700;
    color: var(--text);
  }

  .permissions-head p {
    margin: 0.28rem 0 0;
    font-size: 0.82rem;
    color: var(--muted);
  }

  .permissions-scroll {
    min-height: 0;
    max-height: min(46vh, 30rem);
    overflow: auto;
    border: 1px solid var(--line);
    border-radius: 0.8rem;
    background: var(--panel-soft);
  }

  .permissions-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    table-layout: fixed;
  }

  .permissions-table th,
  .permissions-table td {
    padding: 0.85rem 1rem;
    border-bottom: 1px solid var(--line);
    text-align: left;
    vertical-align: top;
  }

  .permissions-table th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: color-mix(in srgb, var(--panel) 92%, var(--panel-soft));
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--muted);
  }

  .permissions-table tbody tr:last-child td {
    border-bottom: none;
  }

  .module-name-cell {
    width: 11rem;
  }

  .module-name-cell strong {
    display: block;
    color: var(--text);
  }

  .module-description-cell {
    color: var(--muted);
    font-size: 0.83rem;
    line-height: 1.45;
  }

  .module-level-cell {
    width: 11rem;
  }

  .module-level-cell .matrix-select {
    gap: 0;
  }

  .sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  .form-error {
    margin: 0;
    padding: 0.6rem 0.8rem;
    background: color-mix(in srgb, #e53e3e 8%, transparent);
    border: 1px solid color-mix(in srgb, #e53e3e 25%, transparent);
    border-radius: 0.55rem;
    font-size: 0.83rem;
  }

  .modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.6rem;
    margin-top: 0.3rem;
  }

  .modal-cancel {
    padding: 0.55rem 1.1rem;
    background: var(--panel);
    border: 1px solid var(--line);
    color: var(--muted);
    border-radius: 0.6rem;
    font-size: 0.88rem;
    font-weight: 600;
    cursor: pointer;
  }

  .modal-confirm {
    padding: 0.55rem 1.1rem;
    background: #b3261e;
    border: 1px solid #b3261e;
    color: #fff;
    border-radius: 0.6rem;
    font-size: 0.88rem;
    font-weight: 600;
    cursor: pointer;
  }

  @media (max-width: 860px) {
    .field-row {
      grid-template-columns: 1fr;
    }

    .permissions-scroll {
      max-height: min(44vh, 26rem);
    }

    .permissions-table,
    .permissions-table thead,
    .permissions-table tbody,
    .permissions-table tr,
    .permissions-table th,
    .permissions-table td {
      display: block;
    }

    .permissions-table thead {
      display: none;
    }

    .permissions-table tbody {
      display: grid;
    }

    .permissions-table tr {
      display: grid;
      gap: 0.55rem;
      padding: 0.95rem 1rem;
      border-bottom: 1px solid var(--line);
    }

    .permissions-table td {
      width: auto;
      padding: 0;
      border: none;
    }

    .module-level-cell .matrix-select {
      gap: 0.35rem;
    }

    .module-level-cell .matrix-select .sr-only {
      position: static;
      width: auto;
      height: auto;
      margin: 0;
      overflow: visible;
      clip: auto;
      white-space: normal;
      font-size: 0.78rem;
      font-weight: 600;
      color: var(--muted);
    }
  }

  @media (max-width: 720px) {
    .panel-header {
      flex-direction: column;
      align-items: flex-start;
    }
  }
</style>
