<?php

namespace App\Livewire\Admin;

use Illuminate\Support\Facades\Auth;
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 RolePermissionManager extends Component
{
    public string $newRole = '';

    public string $newPermission = '';

    /** Roles that must not be deleted or stripped of core powers. */
    private const PROTECTED_ROLES = ['Admin'];

    private const CORE_PERMISSION = 'manage all';

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

    private function flushCache(): void
    {
        app(PermissionRegistrar::class)->forgetCachedPermissions();
    }

    public function togglePermission(int $roleId, string $permissionName): void
    {
        $role = Role::findOrFail($roleId);

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

                return;
            }
            $role->revokePermissionTo($permissionName);
        } else {
            $role->givePermissionTo($permissionName);
        }

        $this->flushCache();
        $this->dispatch('notify', 'Permisos actualizados');
    }

    public function addRole(): void
    {
        $this->validate([
            'newRole' => 'required|string|max:50|unique:roles,name',
        ], [], ['newRole' => 'nombre de rol']);

        Role::create(['name' => trim($this->newRole)]);
        $this->newRole = '';
        $this->flushCache();
        $this->dispatch('notify', 'Rol creado');
    }

    public function deleteRole(int $roleId): void
    {
        $role = Role::findOrFail($roleId);

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

            return;
        }

        $role->delete();
        $this->flushCache();
        $this->dispatch('notify', 'Rol eliminado');
    }

    public function addPermission(): void
    {
        $this->validate([
            'newPermission' => 'required|string|max:50|unique:permissions,name',
        ], [], ['newPermission' => 'nombre de permiso']);

        Permission::create(['name' => trim($this->newPermission)]);
        $this->newPermission = '';
        $this->flushCache();
        $this->dispatch('notify', 'Permiso creado');
    }

    public function deletePermission(int $permissionId): void
    {
        $permission = Permission::findOrFail($permissionId);

        if ($permission->name === self::CORE_PERMISSION) {
            $this->dispatch('notify', "El permiso '".self::CORE_PERMISSION."' está protegido y no se puede borrar.");

            return;
        }

        $permission->delete();
        $this->flushCache();
        $this->dispatch('notify', 'Permiso eliminado');
    }

    public function render()
    {
        return view('livewire.roles.role-permission-manager', [
            'roles' => Role::with('permissions')->orderBy('name')->get(),
            'permissions' => Permission::orderBy('name')->get(),
        ]);
    }
}
