<?php

namespace App\Livewire\Admin;

use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Livewire\Attributes\Layout;
use Livewire\Component;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
use Spatie\Permission\PermissionRegistrar;

#[Layout('layouts.app')]
class RoleView extends Component
{
    public Role $role;

    public string $tab = 'ficha';   // ficha | permisos

    public $newUserId = '';

    private const PROTECTED_ROLES = ['Admin'];

    private const CORE_PERMISSION = 'manage all';

    public function mount(Role $role): void
    {
        abort_unless(Auth::user()?->can('manage roles'), 403);
        $this->role = $role;
    }

    public function setTab(string $tab): void
    {
        $this->tab = in_array($tab, ['ficha', 'permisos'], true) ? $tab : 'ficha';
    }

    public function togglePermission(string $permissionName): void
    {
        // Admin must always keep the core permission
        if ($this->role->name === 'Admin'
            && $permissionName === self::CORE_PERMISSION
            && $this->role->hasPermissionTo($permissionName)) {
            $this->dispatch('notify', "El rol Admin no puede perder '".self::CORE_PERMISSION."'.");

            return;
        }

        if ($this->role->hasPermissionTo($permissionName)) {
            $this->role->revokePermissionTo($permissionName);
        } else {
            $this->role->givePermissionTo($permissionName);
        }

        app(PermissionRegistrar::class)->forgetCachedPermissions();
        $this->role->load('permissions');
        $this->dispatch('notify', 'Permisos actualizados');
    }

    public function addUser(): void
    {
        $this->validate(['newUserId' => 'required|exists:users,id'], [], ['newUserId' => 'usuario']);

        User::findOrFail($this->newUserId)->assignRole($this->role->name);
        $this->newUserId = '';
        app(PermissionRegistrar::class)->forgetCachedPermissions();
        $this->dispatch('notify', 'Usuario añadido al rol');
    }

    public function removeUser(int $userId): void
    {
        User::findOrFail($userId)->removeRole($this->role->name);
        app(PermissionRegistrar::class)->forgetCachedPermissions();
        $this->dispatch('notify', 'Usuario quitado del rol');
    }

    public function setGroup(string $group, bool $enabled): void
    {
        $names = Permission::where('group', $group)->pluck('name');

        foreach ($names as $name) {
            // Admin must always keep the core permission
            if (! $enabled && $this->role->name === 'Admin' && $name === self::CORE_PERMISSION) {
                continue;
            }
            $enabled ? $this->role->givePermissionTo($name) : $this->role->revokePermissionTo($name);
        }

        app(PermissionRegistrar::class)->forgetCachedPermissions();
        $this->role->load('permissions');
        $this->dispatch('notify', $enabled ? 'Permisos del grupo activados' : 'Permisos del grupo desactivados');
    }

    public function delete()
    {
        if (in_array($this->role->name, self::PROTECTED_ROLES, true)) {
            $this->dispatch('notify', "El rol '{$this->role->name}' está protegido y no se puede borrar.");

            return;
        }
        $this->role->delete();
        app(PermissionRegistrar::class)->forgetCachedPermissions();
        session()->flash('message', 'Rol eliminado.');

        return $this->redirect(route('admin.roles'), navigate: true);
    }

    /** Section title for a permission name (groups by the resource / last word). */
    private function sectionFor(string $name): string
    {
        if ($name === self::CORE_PERMISSION) {
            return 'General';
        }
        $resource = Str::afterLast($name, ' ');

        return Str::headline($resource ?: 'General');
    }

    public function render()
    {
        $users = $this->role->users()
            ->orderBy('first_name')
            ->orderBy('name')
            ->get();

        $order = [
            'Proyectos', 'Fases y progreso', 'Capas y elementos', 'Inspecciones',
            'Incidencias', 'Empresas', 'Usuarios', 'Roles', 'Informes', 'Archivos', 'General',
        ];

        $grouped = Permission::orderBy('name')->get()
            ->groupBy(fn ($perm) => $perm->group ?: $this->sectionFor($perm->name))
            ->sortBy(function ($perms, $section) use ($order) {
                $i = array_search($section, $order, true);

                return $i === false ? 999 : $i;
            });

        $availableUsers = User::whereDoesntHave('roles', fn ($q) => $q->where('roles.id', $this->role->id))
            ->orderBy('first_name')->orderBy('name')->get();

        return view('livewire.roles.role-view', [
            'users' => $users,
            'availableUsers' => $availableUsers,
            'grouped' => $grouped,
            'rolePerms' => $this->role->permissions->pluck('name')->toArray(),
            'isProtected' => in_array($this->role->name, self::PROTECTED_ROLES, true),
        ]);
    }
}
