<?php

namespace App\Modules\Settings\Rbac\Services;

use App\Models\User;
use App\Modules\Settings\Rbac\Repositories\PermissionRepository;
use Illuminate\Support\Facades\Cache;

class TenantPermissionEvaluator
{
    private const CACHE_PREFIX = 'tenant_perm:user:';

    public function __construct(
        private readonly PermissionRepository $permissions,
    ) {}

    public function allows(User $user, string $ability, array $arguments = []): bool
    {
        if (! $user->is_active || $user->tenant_id === null) {
            return false;
        }
        if ($user->isTenantOwner()) {
            return $this->argumentsTenantSafe($user, $arguments);
        }
        $slugs = $this->slugsForUser($user);
        if (! in_array($ability, $slugs, true)) {
            return false;
        }

        return $this->argumentsTenantSafe($user, $arguments);
    }

    public function hasAnyAbility(User $user): bool
    {
        if (! $user->is_active || $user->tenant_id === null) {
            return false;
        }
        if ($user->isTenantOwner()) {
            return true;
        }

        return $this->slugsForUser($user) !== [];
    }

    /**
     * @return list<string>
     */
    public function slugsForUser(User $user): array
    {
        if (! $user->is_active || $user->tenant_id === null) {
            return [];
        }

        return Cache::remember(
            self::CACHE_PREFIX.$user->id,
            120,
            fn (): array => $this->permissions->permissionSlugsForUser($user),
        );
    }

    public static function forgetCacheForUser(User $user): void
    {
        Cache::forget(self::CACHE_PREFIX.$user->id);
    }

    private function argumentsTenantSafe(User $user, array $arguments): bool
    {
        foreach ($arguments as $arg) {
            if (! is_object($arg)) {
                continue;
            }
            if (! property_exists($arg, 'tenant_id')) {
                continue;
            }
            if ((int) $arg->tenant_id !== (int) $user->tenant_id) {
                return false;
            }
        }

        return true;
    }
}
