{{--
    Per-user permission override editor — see App\Filament\Forms\Components\PermissionOverridePicker.

    Two deferred `wire:model` checkbox groups back this view: `<state>.grant` and
    `<state>.revoke`, bound exactly the way Filament's own CheckboxList binds an
    array, so toggling a permission never costs a server round-trip. A permission
    in neither group is INHERITED — it follows the user's roles for as long as they
    hold them. A permission in either group is PINNED to this user and survives any
    later change to those roles.

    Each chip therefore has two independent inputs to its appearance:
      data-inherited  server-rendered: do the selected roles grant this?
      data-state      client-driven:   inherit | grant | revoke

    Those are deliberately kept as HTML attributes rather than Alpine state. The
    inherited flag is re-rendered by Livewire whenever the role selection changes,
    while data-state is updated instantly by Alpine on click — expressing the four
    combinations in CSS lets each side update without having to sync the other.
--}}
@php
    use Filament\Support\Icons\Heroicon;
    use Filament\Support\Enums\IconSize;

    $statePath = $getStatePath();
    $wireModel = $applyStateBindingModifiers('wire:model');
    $isDisabled = $isDisabled();

    $overrides = \App\Filament\Forms\Components\PermissionOverridePicker::normalize($getState());
    $granted = array_flip($overrides['grant']);
    $revoked = array_flip($overrides['revoke']);
    $inheritedSet = array_flip($inherited);
@endphp

<x-dynamic-component :component="$getFieldWrapperView()" :field="$field">
    <div
        x-data="{
            search: '',
            open: {},
            onlyOverrides: false,
            counts: {},

            init() {
                this.refreshAllCounts();
            },

            // ── Reading a chip ────────────────────────────────────────────
            isInherited(chip) {
                return chip.dataset.inherited === '1';
            },

            stateOf(chip) {
                return chip.dataset.state;
            },

            isEffective(chip) {
                const state = this.stateOf(chip);

                return state === 'grant' ? true : (state === 'revoke' ? false : this.isInherited(chip));
            },

            isOverridden(chip) {
                return this.stateOf(chip) !== 'inherit';
            },

            // ── Writing a chip ───────────────────────────────────────────
            // One click flips the effective answer, then records the cheapest
            // representation of it: if the roles already say what the admin
            // wants, no override is stored at all, so the permission keeps
            // following the roles.
            toggle(chip) {
                if (chip.dataset.disabled === '1') return;

                const desired = ! this.isEffective(chip);
                this.apply(chip, desired === this.isInherited(chip) ? 'inherit' : (desired ? 'grant' : 'revoke'));
                this.refreshAllCounts();
            },

            apply(chip, next) {
                if (chip.dataset.disabled === '1') return;

                const grant = chip.querySelector('.perm-grant');
                const revoke = chip.querySelector('.perm-revoke');

                // .click() rather than .checked — it is what notifies Livewire's
                // own change listener, the same trick the role picker uses.
                if (grant.checked !== (next === 'grant')) grant.click();
                if (revoke.checked !== (next === 'revoke')) revoke.click();

                chip.dataset.state = next;
            },

            // ── Bulk actions ─────────────────────────────────────────────
            setAll(root, next) {
                this.chipsIn(root).forEach((chip) => this.apply(chip, next));
                this.refreshAllCounts();
            },

            grantAll(root) {
                this.chipsIn(root).forEach((chip) => {
                    this.apply(chip, this.isInherited(chip) ? 'inherit' : 'grant');
                });
                this.refreshAllCounts();
            },

            revokeAll(root) {
                this.chipsIn(root).forEach((chip) => {
                    this.apply(chip, this.isInherited(chip) ? 'revoke' : 'inherit');
                });
                this.refreshAllCounts();
            },

            chipsIn(root) {
                // Bulk actions deliberately apply to what the operator can
                // currently see, so an active search or the overrides-only
                // filter narrows them rather than being silently ignored.
                return [...root.querySelectorAll('.perm-chip')].filter((chip) => this.chipVisible(chip));
            },

            // ── Filtering ────────────────────────────────────────────────
            // Matches on search relevance, not layout visibility: a collapsed
            // section's body sits behind x-collapse's display:none, so an
            // offsetParent-based check would silently skip its chips.
            chipVisible(chip) {
                if (this.onlyOverrides && ! this.isOverridden(chip)) return false;

                return this.rowMatches(chip.closest('.perm-row'));
            },

            rowMatches(el) {
                if (! el) return false;

                const q = this.search.trim().toLowerCase();
                if (! q) return true;

                return (el.innerText || '').toLowerCase().includes(q);
            },

            sectionMatches(el) {
                const q = this.search.trim().toLowerCase();
                if (q && ! [...el.querySelectorAll('.perm-row')].some((row) => (row.innerText || '').toLowerCase().includes(q))) {
                    return false;
                }

                if (this.onlyOverrides) {
                    return [...el.querySelectorAll('.perm-chip')].some((chip) => this.isOverridden(chip));
                }

                return true;
            },

            // ── Counters ─────────────────────────────────────────────────
            refreshSectionCounts(sectionEl) {
                const chips = [...sectionEl.querySelectorAll('.perm-chip')];

                this.counts[sectionEl.dataset.section] = {
                    total: chips.length,
                    granted: chips.filter((chip) => this.isEffective(chip)).length,
                    overrides: chips.filter((chip) => this.isOverridden(chip)).length,
                };
            },

            refreshAllCounts() {
                // Scoped to this picker, not the document: the section keys are
                // positional ($loop index), so a second matrix on the same page
                // would otherwise overwrite this one's counters.
                this.$root.querySelectorAll('[data-section]').forEach((el) => this.refreshSectionCounts(el));
            },

            total(key) {
                return Object.values(this.counts).reduce((sum, c) => sum + (c?.[key] ?? 0), 0);
            },
        }"
        class="fi-permission-override-picker space-y-3"
    >
        {{--
            Recomputes the counters after Livewire re-renders the matrix with a
            different inherited set (i.e. when the role selection changes). The
            wire:key is derived from that set, so Livewire replaces this node,
            and Alpine runs x-init on the replacement.
        --}}
        <span class="hidden" x-init="refreshAllCounts()" wire:key="perm-inherited-{{ md5(json_encode($inherited)) }}"></span>

        <style>
            /* The four states a permission can be in. Kept as CSS on the
               data-* attribute pair so the server-rendered inherited flag and
               Alpine's click-driven state can each change independently. */
            .fi-permission-override-picker .perm-chip-face {
                display: inline-flex;
                align-items: center;
                gap: 0.375rem;
                border-radius: 9999px;
                border-width: 1px;
                padding: 0.375rem 0.75rem;
                font-size: 0.75rem;
                font-weight: 500;
                line-height: 1rem;
                cursor: pointer;
                transition: background-color .12s, border-color .12s, color .12s;
                border-color: rgb(229 231 235);
                background-color: rgb(255 255 255);
                color: rgb(75 85 99);
            }
            .dark .fi-permission-override-picker .perm-chip-face {
                border-color: rgb(255 255 255 / .1);
                background-color: rgb(31 41 55);
                color: rgb(209 213 219);
            }
            .fi-permission-override-picker .perm-chip-face:hover {
                border-color: var(--primary-500);
                color: var(--primary-600);
            }

            /* Granted — whether that came from the role or from an override. */
            .fi-permission-override-picker .perm-chip[data-inherited='1'][data-state='inherit'] .perm-chip-face,
            .fi-permission-override-picker .perm-chip[data-state='grant'] .perm-chip-face {
                border-color: var(--primary-600);
                background-color: var(--primary-600);
                color: var(--primary-foreground, #fff);
            }

            /* Revoked from the role: struck through, so it reads as "the role
               says yes, this user says no" rather than merely "off". */
            .fi-permission-override-picker .perm-chip[data-state='revoke'] .perm-chip-face {
                border-color: rgb(220 38 38);
                background-color: rgb(254 242 242);
                color: rgb(185 28 28);
                text-decoration-line: line-through;
            }
            .dark .fi-permission-override-picker .perm-chip[data-state='revoke'] .perm-chip-face {
                border-color: rgb(248 113 113 / .5);
                background-color: rgb(127 29 29 / .25);
                color: rgb(252 165 165);
            }

            /* The override marker: a dot on any chip that no longer follows the
               role, so a pinned permission is identifiable at a glance. */
            .fi-permission-override-picker .perm-chip .perm-pin { display: none; }
            .fi-permission-override-picker .perm-chip:not([data-state='inherit']) .perm-pin { display: inline-block; }

            .fi-permission-override-picker .perm-chip[data-state='grant'] .perm-chip-face { box-shadow: inset 0 0 0 1px var(--primary-foreground, #fff); }

            /* Only the granted-by-role state shows the tick. */
            .fi-permission-override-picker .perm-chip .perm-tick { visibility: hidden; }
            .fi-permission-override-picker .perm-chip[data-inherited='1'][data-state='inherit'] .perm-tick,
            .fi-permission-override-picker .perm-chip[data-state='grant'] .perm-tick { visibility: visible; }

            .fi-permission-override-picker .perm-chip[data-disabled='1'] .perm-chip-face { opacity: .5; cursor: not-allowed; }
        </style>

        {{-- ── Toolbar ─────────────────────────────────────────────────── --}}
        <div class="flex flex-col gap-2 sm:flex-row sm:items-center">
            <div class="relative flex-1">
                <x-filament::icon icon="heroicon-m-magnifying-glass" class="pointer-events-none absolute inset-y-0 start-3 my-auto h-4 w-4 text-gray-400 dark:text-gray-500" />
                <input
                    type="search"
                    x-model="search"
                    placeholder="Search modules or actions…"
                    class="fi-input w-full rounded-lg border-gray-300 ps-9 dark:bg-gray-800"
                >
            </div>

            <div class="flex items-center gap-3 text-xs text-gray-500 dark:text-gray-400">
                <span class="tabular-nums">
                    <span x-text="total('granted')"></span> of <span x-text="total('total')"></span> effective
                </span>
                <button
                    type="button"
                    x-on:click="onlyOverrides = ! onlyOverrides"
                    class="rounded-md px-2 py-1 font-medium tabular-nums"
                    x-bind:class="onlyOverrides
                        ? 'bg-primary-600 text-white'
                        : 'text-primary-600 hover:text-primary-500 dark:text-primary-400'"
                >
                    <span x-text="total('overrides')"></span> override<span x-show="total('overrides') !== 1">s</span>
                </button>
                <div class="flex items-center gap-1">
                    <button
                        type="button"
                        x-on:click="grantAll($root)"
                        @disabled($isDisabled)
                        class="font-medium text-primary-600 hover:text-primary-500 disabled:opacity-50 dark:text-primary-400"
                    >
                        Grant all
                    </button>
                    <span class="text-gray-300 dark:text-white/10">·</span>
                    <button
                        type="button"
                        x-on:click="revokeAll($root)"
                        @disabled($isDisabled)
                        class="font-medium text-gray-500 hover:text-danger-600 disabled:opacity-50 dark:text-gray-400 dark:hover:text-danger-400"
                    >
                        Revoke all
                    </button>
                    <span class="text-gray-300 dark:text-white/10">·</span>
                    <button
                        type="button"
                        x-on:click="setAll($root, 'inherit')"
                        @disabled($isDisabled)
                        class="font-medium text-gray-500 hover:text-gray-700 disabled:opacity-50 dark:text-gray-400 dark:hover:text-gray-200"
                    >
                        Reset to roles
                    </button>
                </div>
            </div>
        </div>

        <p class="text-xs text-gray-500 dark:text-gray-400">
            Permissions follow this user's roles unless you change one here. A changed permission is
            <span class="font-medium text-gray-700 dark:text-gray-200">pinned to this user</span> —
            marked with a dot — and stays as you set it even if their roles change later.
        </p>

        {{-- ── Sections ────────────────────────────────────────────────── --}}
        @foreach ($groups as $sectionIndex => $section)
            @php
                $sectionIcon = $section['icon']
                    ? Heroicon::tryFrom($section['icon'])?->getIconForSize(IconSize::Medium)
                    : 'heroicon-m-squares-2x2';
                $sectionKey = "section-{$sectionIndex}";
            @endphp

            <div
                x-show="sectionMatches($el)"
                class="overflow-hidden rounded-xl border border-gray-200 bg-white shadow-sm dark:border-white/10 dark:bg-gray-900"
            >
                {{-- Section header ─────────────────────────────────────── --}}
                <button
                    type="button"
                    x-on:click="open['{{ $sectionKey }}'] = ! open['{{ $sectionKey }}']"
                    class="flex w-full items-center gap-3 px-4 py-3 text-start hover:bg-gray-50 dark:hover:bg-white/5"
                >
                    <span class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary-50 text-primary-600 dark:bg-primary-500/10 dark:text-primary-400">
                        <x-filament::icon :icon="$sectionIcon" class="h-4 w-4" />
                    </span>

                    <span class="min-w-0 flex-1">
                        <span class="block truncate text-sm font-semibold text-gray-900 dark:text-white">{{ $section['section'] }}</span>
                        <span class="block text-xs text-gray-500 dark:text-gray-400">
                            <span x-text="counts['{{ $sectionKey }}']?.granted ?? 0"></span> of
                            <span x-text="counts['{{ $sectionKey }}']?.total ?? 0"></span> effective
                            <template x-if="(counts['{{ $sectionKey }}']?.overrides ?? 0) > 0">
                                <span class="text-amber-600 dark:text-amber-500">
                                    · <span x-text="counts['{{ $sectionKey }}'].overrides"></span> pinned
                                </span>
                            </template>
                        </span>
                    </span>

                    <span class="hidden h-1.5 w-24 overflow-hidden rounded-full bg-gray-100 sm:block dark:bg-white/10">
                        <span
                            class="block h-full rounded-full bg-primary-500 transition-all"
                            x-bind:style="'width: ' + (counts['{{ $sectionKey }}']?.total
                                ? Math.round((counts['{{ $sectionKey }}']?.granted ?? 0) / counts['{{ $sectionKey }}'].total * 100)
                                : 0) + '%'"
                        ></span>
                    </span>

                    <x-filament::icon
                        icon="heroicon-m-chevron-down"
                        class="h-4 w-4 shrink-0 text-gray-400 transition-transform"
                        x-bind:class="open['{{ $sectionKey }}'] ? '' : '-rotate-90'"
                    />
                </button>

                {{-- Section body ───────────────────────────────────────── --}}
                <div
                    x-show="open['{{ $sectionKey }}'] || search || onlyOverrides"
                    x-collapse
                    class="border-t border-gray-100 px-4 py-3 dark:border-white/10"
                >
                    <div data-section="{{ $sectionKey }}" class="space-y-4">
                        @unless ($isDisabled)
                            <div class="flex items-center justify-between gap-2 border-b border-gray-100 pb-2 dark:border-white/10">
                                <span class="text-[11px] font-medium uppercase tracking-wide text-gray-400 dark:text-gray-500">This section</span>
                                <span class="flex items-center gap-1.5 text-[11px] font-medium text-gray-400">
                                    <button type="button" x-on:click="grantAll($el.closest('[data-section]'))" class="text-primary-600 hover:text-primary-500 dark:text-primary-400">grant all</button>
                                    <span class="text-gray-300 dark:text-white/10">·</span>
                                    <button type="button" x-on:click="revokeAll($el.closest('[data-section]'))" class="hover:text-danger-600 dark:hover:text-danger-400">revoke all</button>
                                    <span class="text-gray-300 dark:text-white/10">·</span>
                                    <button type="button" x-on:click="setAll($el.closest('[data-section]'), 'inherit')" class="hover:text-gray-600 dark:hover:text-gray-200">reset</button>
                                </span>
                            </div>
                        @endunless

                        @foreach ($section['modules'] as $module)
                            @php
                                $moduleIcon = $module['icon']
                                    ? Heroicon::tryFrom($module['icon'])?->getIconForSize(IconSize::Small)
                                    : 'heroicon-c-squares-2x2';
                            @endphp

                            <div class="perm-row" x-show="rowMatches($el)">
                                <div class="mb-2 flex items-center gap-2">
                                    <x-filament::icon :icon="$moduleIcon" class="h-3.5 w-3.5 text-gray-400" />
                                    <span class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">{{ $module['label'] }}</span>

                                    @unless ($isDisabled)
                                        <span class="ms-auto flex items-center gap-2 text-[11px] font-medium text-gray-400">
                                            <button type="button" x-on:click="grantAll($el.closest('.perm-row'))" class="hover:text-primary-600 dark:hover:text-primary-400">grant all</button>
                                            <button type="button" x-on:click="revokeAll($el.closest('.perm-row'))" class="hover:text-danger-600 dark:hover:text-danger-400">revoke all</button>
                                            <button type="button" x-on:click="setAll($el.closest('.perm-row'), 'inherit')" class="hover:text-gray-600 dark:hover:text-gray-200">reset</button>
                                        </span>
                                    @endunless
                                </div>

                                <div class="flex flex-wrap gap-1.5">
                                    @foreach ($module['actions'] as $action)
                                        @php
                                            $permissionName = "{$module['key']}.{$action}";
                                            $isInherited = isset($inheritedSet[$permissionName]);
                                            $state = isset($granted[$permissionName])
                                                ? 'grant'
                                                : (isset($revoked[$permissionName]) ? 'revoke' : 'inherit');
                                        @endphp

                                        <span
                                            class="perm-chip"
                                            data-perm="{{ $permissionName }}"
                                            data-inherited="{{ $isInherited ? '1' : '0' }}"
                                            data-state="{{ $state }}"
                                            data-disabled="{{ $isDisabled ? '1' : '0' }}"
                                            x-show="chipVisible($el)"
                                        >
                                            <input
                                                type="checkbox"
                                                class="perm-grant sr-only"
                                                value="{{ $permissionName }}"
                                                wire:loading.attr="disabled"
                                                @disabled($isDisabled)
                                                {{ $wireModel }}="{{ $statePath }}.grant"
                                                @checked($state === 'grant')
                                            >
                                            <input
                                                type="checkbox"
                                                class="perm-revoke sr-only"
                                                value="{{ $permissionName }}"
                                                wire:loading.attr="disabled"
                                                @disabled($isDisabled)
                                                {{ $wireModel }}="{{ $statePath }}.revoke"
                                                @checked($state === 'revoke')
                                            >

                                            <button
                                                type="button"
                                                class="perm-chip-face"
                                                x-on:click="toggle($el.closest('.perm-chip'))"
                                                x-bind:title="(isInherited($el.closest('.perm-chip')) ? 'Granted by role' : 'Not granted by role')
                                                    + ' · ' + ({
                                                        inherit: 'inherited',
                                                        grant: 'granted for this user only',
                                                        revoke: 'revoked for this user only',
                                                    })[stateOf($el.closest('.perm-chip'))]"
                                            >
                                                <x-filament::icon icon="heroicon-m-check" class="perm-tick h-3 w-3" />
                                                <span class="capitalize">{{ str_replace('_', ' ', $action) }}</span>
                                                <span class="perm-pin h-1.5 w-1.5 rounded-full bg-amber-400"></span>
                                            </button>
                                        </span>
                                    @endforeach
                                </div>
                            </div>
                        @endforeach
                    </div>
                </div>
            </div>
        @endforeach
    </div>
</x-dynamic-component>
