<?php

namespace App\Services;

use App\Models\User;
use Illuminate\Support\Collection;
use Spatie\Permission\Models\Role;

class RoleAssignmentService
{
    private const ROLE_HIERARCHY = [
        'admin' => ['admin', 'hr-head', 'hr-officer', 'member', 'user'],
        'hr-head' => ['hr-officer', 'member', 'user'],
        'hr-officer' => ['member', 'user'],
        'member' => ['user'],
        'user' => [],
    ];

    public function allowedRoles(User $actor): array
    {
        $actorRole = $this->resolvePrimaryRole($actor);

        if ($actorRole === null) {
            return [];
        }

        if ($actorRole === 'admin') {
            return Role::pluck('name')->all();
        }

        return self::ROLE_HIERARCHY[$actorRole] ?? [];
    }

    public function assign(User $actor, User $target, array $roles): void
    {
        $allowed = collect($this->allowedRoles($actor));

        if ($allowed->isEmpty() && !$actor->hasRole('admin')) {
            abort(403, 'You are not allowed to assign roles.');
        }

        $invalid = collect($roles)
            ->reject(fn ($role) => $allowed->contains($role) || $actor->hasRole('admin'));

        if ($invalid->isNotEmpty()) {
            abort(422, 'Cannot assign roles: '. $invalid->implode(', '));
        }

        $target->syncRoles($roles);
    }

    private function resolvePrimaryRole(User $actor): ?string
    {
        $roles = $actor->getRoleNames();

        if ($roles->isEmpty()) {
            return null;
        }

        foreach (array_keys(self::ROLE_HIERARCHY) as $role) {
            if ($roles->contains($role)) {
                return $role;
            }
        }

        return $roles->first();
    }
}
