<?php

declare(strict_types=1);

namespace apexl\Io\modules\user\services;

use apexl\Io\exceptions\RecordNotFoundException;
use apexl\Io\modules\user\collections\roleCollection;
use apexl\Io\modules\user\entities\roleEntity;
use apexl\Io\modules\user\entities\userEntity;
use apexl\Vault\Vault;

final readonly class userRoleManagerService
{
    const TABLE__USERS_ROLES = 'users__roles';

    public function __construct(private userEntity $user, private Vault $vault,)
    {
    }

    public function add(string|int|roleEntity $role): void
    {
        try {
            $roleId = $this->ensureRoleId($role);
        } catch (RecordNotFoundException) {
            return;
        }

        if ($this->has($roleId)) {
            return;
        }

        $this->vault->insert(self::TABLE__USERS_ROLES)
            ->fields([
                'user' => $this->user->id,
                'role' => $roleId,
            ])->execute();

    }

    /**
     * @throws RecordNotFoundException
     */
    private function ensureRoleId(string|roleEntity|int $role): int
    {
        if (is_string($role)) {
            $_role = new roleEntity();
            $_role->loadByName($role);
            if (!$_role->id) {
                throw new RecordNotFoundException(sprintf('Role %s not found', $role));
            }

            return $_role->id;
        }

        if ($role instanceof roleEntity) {
            return $role->id;
        }

        return $role;
    }

    public function has(string|int|roleEntity $role): bool
    {
        try {
            $roleId = $this->ensureRoleId($role);
        } catch (RecordNotFoundException) {
            return false;
        }

        return $this->roles()->exists(fn(roleEntity $role): bool => $role->id === $roleId);
    }

    public function roles(): roleCollection
    {
        $userId = $this->user->id;

        return roleCollection::createFromQueryResult(
            $this->vault->select(self::TABLE__USERS_ROLES)
                ->fields('role')
                ->where('user', $userId)
                ->execute()
                ->fetchAll()
        );
    }

    public function clear(): void
    {
        $this->vault->delete(self::TABLE__USERS_ROLES)
            ->where('user', $this->user->id)
            ->execute();
    }

    public function remove(int|roleEntity $role): void
    {
        $roleId = $this->ensureRoleId($role);
        $this->vault->delete(self::TABLE__USERS_ROLES)
            ->where('user', $this->user->id)
            ->where('permission', $roleId)
            ->execute();
    }
}
