<?php

namespace App\Services\Authorization;

use App\Models\Permission;
use App\Models\Role;
use App\Models\User;
use Illuminate\Support\Facades\DB;

class AuthorizationAssignmentService
{
    /** @param array<int, int|string> $roleIds */
    public function syncUserRoleIds(User $user, array $roleIds): void
    {
        $ids = collect($roleIds)
            ->map(fn ($id) => (int) $id)
            ->filter()
            ->unique()
            ->values();

        $roles = Role::query()->whereKey($ids)->get();

        DB::transaction(function () use ($user, $roles): void {
            $user->syncRoles($roles);
        });
    }

    public function assignUserRole(User $user, Role|string $role): void
    {
        DB::transaction(function () use ($user, $role): void {
            $user->assignRole($role);
        });
    }

    /** @param array<int, int|string> $permissionIds */
    public function syncRolePermissionIds(Role $role, array $permissionIds): void
    {
        $ids = collect($permissionIds)
            ->map(fn ($id) => (int) $id)
            ->filter()
            ->unique()
            ->values();

        $permissions = Permission::query()->whereKey($ids)->get();

        DB::transaction(function () use ($role, $permissions): void {
            $role->syncPermissions($permissions);
        });
    }

    /** @param array<int, string> $permissionNames */
    public function giveRolePermissionNames(Role $role, array $permissionNames): void
    {
        $names = collect($permissionNames)
            ->map(fn ($name) => trim((string) $name))
            ->filter()
            ->unique()
            ->values();

        if ($names->isEmpty()) {
            return;
        }

        $permissions = Permission::query()->whereIn('name', $names)->get();

        DB::transaction(function () use ($role, $permissions): void {
            $role->givePermissionTo($permissions);
        });
    }
}
