{{--
    Grouped, searchable permission picker — see App\Filament\Forms\Components\PermissionPicker.

    State is an array of "module.action" names, bound with the same deferred
    `wire:model` binding Filament's CheckboxList uses, so toggling a permission
    never triggers a server round-trip. Search, collapse and counters are pure
    client-side Alpine.
--}}
@php
    use Filament\Support\Icons\Heroicon;
    use Filament\Support\Enums\IconSize;

    $statePath = $getStatePath();
    $wireModel = $applyStateBindingModifiers('wire:model');
    // Livewire syncs an all-unchecked checkbox group back as `false` rather
    // than `[]` or `null` — array_flip(null ?? []) alone doesn't catch that.
    $selected = array_flip(is_array($state = $getState()) ? $state : []);
    $isDisabled = $isDisabled();
@endphp

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

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

            rowMatches(el) {
                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) return true;
                return [...el.querySelectorAll('.perm-row')].some((row) => {
                    return (row.innerText || '').toLowerCase().includes(q);
                });
            },

            refreshSectionCounts(sectionEl) {
                const key = sectionEl.dataset.section;
                const inputs = sectionEl.querySelectorAll('input[type=checkbox]');
                this.counts[key] = {
                    total: inputs.length,
                    checked: [...inputs].filter((i) => i.checked).length,
                };
            },

            refreshAllCounts() {
                document.querySelectorAll('[data-section]').forEach((el) => this.refreshSectionCounts(el));
            },

            onSectionChange(sectionEl) {
                this.refreshSectionCounts(sectionEl);
            },

            setAll(inputs, on) {
                inputs.forEach((i) => { if (i.checked !== on && ! i.disabled) i.click(); });
            },

            grantSection(sectionEl) {
                this.setAll([...sectionEl.querySelectorAll('input[type=checkbox]')], true);
                this.refreshSectionCounts(sectionEl);
            },

            revokeSection(sectionEl) {
                this.setAll([...sectionEl.querySelectorAll('input[type=checkbox]')], false);
                this.refreshSectionCounts(sectionEl);
            },

            grantModule(rowEl) {
                this.setAll([...rowEl.querySelectorAll('input[type=checkbox]')], true);
                this.refreshAllCounts();
            },

            revokeModule(rowEl) {
                this.setAll([...rowEl.querySelectorAll('input[type=checkbox]')], false);
                this.refreshAllCounts();
            },

            visibleCheckboxes() {
                // Matches on search relevance, not layout visibility: a
                // collapsed (unopened) section's body sits behind x-collapse's
                // display:none, so offsetParent-based checks used to think
                // its checkboxes didn't exist and silently skipped them.
                return [...document.querySelectorAll('[data-section]')]
                    .filter((el) => this.sectionMatches(el))
                    .flatMap((el) => [...el.querySelectorAll('.perm-row')])
                    .filter((row) => this.rowMatches(row))
                    .flatMap((row) => [...row.querySelectorAll('input[type=checkbox]')]);
            },

            grantAllVisible() {
                this.setAll(this.visibleCheckboxes(), true);
                this.refreshAllCounts();
            },

            revokeAllVisible() {
                this.setAll(this.visibleCheckboxes(), false);
                this.refreshAllCounts();
            },

            totalSelected() {
                return Object.values(this.counts).reduce((sum, c) => sum + (c?.checked ?? 0), 0);
            },

            totalAvailable() {
                return Object.values(this.counts).reduce((sum, c) => sum + (c?.total ?? 0), 0);
            },
        }"
        class="fi-permission-picker space-y-3"
    >
        {{-- ── 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="totalSelected()"></span> of <span x-text="totalAvailable()"></span> granted
                </span>
                <div class="flex items-center gap-1">
                    <button
                        type="button"
                        x-on:click="grantAllVisible()"
                        @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="revokeAllVisible()"
                        @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>
                </div>
            </div>
        </div>

        {{-- ── 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="! search || 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 }}']?.checked ?? 0"></span> of
                            <span x-text="counts['{{ $sectionKey }}']?.total ?? 0"></span> permissions granted
                        </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 }}']?.checked ?? 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"
                    x-collapse
                    class="border-t border-gray-100 px-4 py-3 dark:border-white/10"
                >
                    <div class="mb-3 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>
                        <div class="flex items-center gap-1.5">
                            <button
                                type="button"
                                x-on:click="grantSection($el.closest('[data-section]'))"
                                @disabled($isDisabled)
                                class="text-[11px] 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="revokeSection($el.closest('[data-section]'))"
                                @disabled($isDisabled)
                                class="text-[11px] font-medium text-gray-500 hover:text-danger-600 disabled:opacity-50 dark:text-gray-400 dark:hover:text-danger-400"
                            >
                                Revoke all
                            </button>
                        </div>
                    </div>

                    <div
                        data-section="{{ $sectionKey }}"
                        x-on:change="onSectionChange($el)"
                        class="space-y-4"
                    >
                        @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-bind:class="rowMatches($el) ? '' : 'hidden'">
                                <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>
                                    <div class="ms-auto flex items-center gap-1.5">
                                        <button
                                            type="button"
                                            x-on:click="grantModule($el.closest('.perm-row'))"
                                            @disabled($isDisabled)
                                            class="text-[11px] font-medium text-primary-600 hover:text-primary-500 disabled:opacity-50 dark:text-primary-400"
                                        >
                                            Grant
                                        </button>
                                        <span class="text-gray-300 dark:text-white/10">·</span>
                                        <button
                                            type="button"
                                            x-on:click="revokeModule($el.closest('.perm-row'))"
                                            @disabled($isDisabled)
                                            class="text-[11px] font-medium text-gray-500 hover:text-danger-600 disabled:opacity-50 dark:text-gray-400 dark:hover:text-danger-400"
                                        >
                                            Revoke
                                        </button>
                                    </div>
                                </div>

                                <div class="flex flex-wrap gap-1.5">
                                    @foreach ($module['actions'] as $action)
                                        @php
                                            $permissionName = "{$module['key']}.{$action}";
                                        @endphp

                                        <label
                                            class="group relative inline-flex cursor-pointer"
                                        >
                                            <input
                                                type="checkbox"
                                                value="{{ $permissionName }}"
                                                wire:loading.attr="disabled"
                                                @disabled($isDisabled)
                                                {{ $wireModel }}="{{ $statePath }}"
                                                @checked(isset($selected[$permissionName]))
                                                class="peer sr-only"
                                            >
                                            <span
                                                class="inline-flex items-center gap-1.5 rounded-full border px-3 py-1.5 text-xs font-medium transition
                                                       border-gray-200 bg-white text-gray-600 hover:border-primary-400 hover:text-primary-600
                                                       peer-checked:border-primary-600 peer-checked:bg-primary-600 peer-checked:text-white
                                                       peer-disabled:opacity-50
                                                       peer-focus-visible:ring-2 peer-focus-visible:ring-primary-500 peer-focus-visible:ring-offset-1
                                                       dark:border-white/10 dark:bg-gray-800 dark:text-gray-300
                                                       dark:peer-checked:border-primary-500 dark:peer-checked:bg-primary-500 dark:peer-checked:text-white"
                                            >
                                                <x-filament::icon icon="heroicon-m-check" class="h-3 w-3 opacity-0 transition group-has-checked:opacity-100" />
                                                <span class="capitalize">{{ $action }}</span>
                                            </span>
                                        </label>
                                    @endforeach
                                </div>
                            </div>
                        @endforeach
                    </div>
                </div>
            </div>
        @endforeach
    </div>
</x-dynamic-component>
