<?php

declare(strict_types=1);

namespace HyperfTest\Cases\Unit\Model;

use App\Model\Role;
use App\Model\User;
use PHPUnit\Framework\TestCase;

/**
 * @internal
 * @coversNothing
 */
class UserRoleTest extends TestCase
{
    protected function runInCoroutine(callable $callback): void
    {
        if (\Swoole\Coroutine::getCid() > 0) {
            $callback();
            return;
        }

        $exception = null;
        \Swoole\Coroutine\run(static function () use ($callback, &$exception): void {
            try {
                $callback();
            } catch (\Throwable $e) {
                $exception = $e;
            }
        });
        if ($exception) {
            throw $exception;
        }
    }

    protected function createUserWithRole(string $role_name): User
    {
        $role = Role::query()->where('name', $role_name)->firstOrFail();
        $suffix = bin2hex(random_bytes(4));

        return User::query()->create([
            'username' => 'role_test_' . $suffix,
            'password' => 'Pass_' . $suffix,
            'email' => 'role_test_' . $suffix . '@example.com',
            'status' => 1,
            'role_id' => $role->id,
        ]);
    }

    public function test_user_belongs_to_role(): void
    {
        $this->runInCoroutine(function (): void {
            $user = $this->createUserWithRole('administrator');
            $this->assertNotNull($user->role);
            $this->assertSame('administrator', $user->role->name);
        });
    }

    public function test_is_administrator(): void
    {
        $this->runInCoroutine(function (): void {
            $user = $this->createUserWithRole('administrator');
            $this->assertTrue($user->isAdministrator());
            $this->assertFalse($user->isDeveloper());
            $this->assertFalse($user->isAccessor());
        });
    }

    public function test_is_developer(): void
    {
        $this->runInCoroutine(function (): void {
            $user = $this->createUserWithRole('developer');
            $this->assertFalse($user->isAdministrator());
            $this->assertTrue($user->isDeveloper());
            $this->assertFalse($user->isAccessor());
        });
    }

    public function test_is_accessor(): void
    {
        $this->runInCoroutine(function (): void {
            $user = $this->createUserWithRole('accessor');
            $this->assertFalse($user->isAdministrator());
            $this->assertFalse($user->isDeveloper());
            $this->assertTrue($user->isAccessor());
        });
    }

    public function test_user_without_role(): void
    {
        $this->runInCoroutine(function (): void {
            $suffix = bin2hex(random_bytes(4));
            $user = User::query()->create([
                'username' => 'no_role_' . $suffix,
                'password' => 'Pass_' . $suffix,
                'email' => 'no_role_' . $suffix . '@example.com',
                'status' => 1,
            ]);

            $this->assertNull($user->role);
            $this->assertFalse($user->isAdministrator());
            $this->assertFalse($user->isDeveloper());
            $this->assertFalse($user->isAccessor());
        });
    }
}
