<?php

namespace Tests\App\Controllers\Api;

use App\Controllers\Api\RolePermissionController;
use App\Models\PermissionModel;
use App\Models\RoleModel;
use App\Models\RolePermissionModel;
use App\Models\UserModel;
use CodeIgniter\Test\CIUnitTestCase;

class TestableRolePermissionController extends RolePermissionController
{
    public function setModels(RoleModel $roleModel, PermissionModel $permissionModel, RolePermissionModel $rolePermissionModel, UserModel $userModel): void
    {
        $this->roleModel = $roleModel;
        $this->permissionModel = $permissionModel;
        $this->rolePermissionModel = $rolePermissionModel;
        $this->userModel = $userModel;
    }

    private ?int $currentUserId = 1;

    public function setCurrentUserId(int $id): void
    {
        $this->currentUserId = $id;
    }

    protected function getCurrentUserId(): ?int
    {
        return $this->currentUserId;
    }
}

class RolePermissionControllerTest extends CIUnitTestCase
{
    private $controller;
    private $roleModel;
    private $permissionModel;
    private $rolePermissionModel;
    private $userModel;

    protected function setUp(): void
    {
        parent::setUp();

        $this->roleModel = $this->createMock(RoleModel::class);
        $this->permissionModel = $this->createMock(PermissionModel::class);
        $this->rolePermissionModel = $this->createMock(RolePermissionModel::class);
        $this->userModel = $this->createMock(UserModel::class);

        $this->controller = new TestableRolePermissionController();
        $this->controller->setModels($this->roleModel, $this->permissionModel, $this->rolePermissionModel, $this->userModel);
    }

    public function testRolesListReturnsData()
    {
        $this->roleModel->method('findAll')->willReturn([
            ['id' => 1, 'name' => 'admin'],
        ]);

        $response = $this->controller->roles();
        $this->assertTrue($response['status']);
        $this->assertNotEmpty($response['data']);
    }

    public function testPermissionsListReturnsData()
    {
        $this->permissionModel->method('findAll')->willReturn([
            ['id' => 11, 'name' => 'view_reports'],
        ]);

        $response = $this->controller->permissions();
        $this->assertTrue($response['status']);
        $this->assertNotEmpty($response['data']);
    }

    public function testRolePermissionsReturnsDataForRole()
    {
        $this->rolePermissionModel->method('where')->with('role_id', 2)->willReturnSelf();
        $this->rolePermissionModel->method('findAll')->willReturn([
            ['permission_id' => 5],
        ]);

        $response = $this->controller->rolePermissions(2);
        $this->assertTrue($response['status']);
        $this->assertEquals('Role permissions retrieved successfully', $response['message']);
    }

    public function testUsersListReturnsSummaries()
    {
        $this->userModel->method('select')->willReturnSelf();
        $this->userModel->method('findAll')->willReturn([
            ['id' => 3, 'firstname' => 'Ali', 'lastname' => 'Khan'],
        ]);

        $response = $this->controller->users();
        $this->assertTrue($response['status']);
        $this->assertCount(1, $response['data']);
    }

    public function testAssignRoleSuccess()
    {
        $dbMock = $this->createMock(\CodeIgniter\Database\BaseConnection::class);
        $dbMock->method('transStart')->willReturn(null);
        $dbMock->method('transComplete')->willReturn(null);
        $dbMock->method('transStatus')->willReturn(true);

        if (!class_exists('Config\\FakeDatabase')) {
            eval('namespace Config; class FakeDatabase extends \\Config\\Database {
                public static function connect($group = null, bool $getShared = true) {
                    return $GLOBALS["__fakeDb__"];
                }
            }');
        }
        $GLOBALS['__fakeDb__'] = $dbMock;
        class_alias('Config\\FakeDatabase', 'Config\\Database');

        $this->userRoleModel->method('where')->with('user_id', 7)->willReturnSelf();
        $this->userRoleModel->method('delete')->willReturn(true);
        $this->userRoleModel->method('insert')->willReturn(true);

        $this->controller->setCurrentUserId(12);

        $req = $this->makeRequest('POST', '/api/v1/users/7/roles', ['role_ids' => [1, 2]]);
        $this->controller->setRequest($req);

        $response = $this->controller->assignRole(7);
        $this->assertTrue($response['status']);
        $this->assertEquals('Roles assigned successfully', $response['message']);
    }
}
