<?php

declare(strict_types=1);

namespace App\Modules\Administration\Services;

use App\Modules\Administration\Repositories\RoleRepository;
use RuntimeException;

final class RoleService
{
    public function __construct(
        private RoleRepository $roles
    ) {
    }

    public function all(): array
    {
        return $this->roles->all();
    }

    public function find(int $id): ?array
    {
        return $this->roles->find($id);
    }

    public function create(array $data): void
    {
        $roleName = trim(
            (string) ($data['role_name'] ?? '')
        );

        $description = trim(
            (string) ($data['description'] ?? '')
        );

        if ($roleName === '') {
            throw new RuntimeException(
                'Role name is required.'
            );
        }

        if (
            $this->roles->findByName(
                $roleName
            ) !== null
        ) {
            throw new RuntimeException(
                'Role name already exists.'
            );
        }

        $this->roles->create([
            'role_name' => $roleName,
            'description' => $description,
            'active' => 1,
            'created_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s')
        ]);
    }

    public function update(
        int $id,
        array $data
    ): void {
        $role = $this->roles->find($id);

        if ($role === null) {
            throw new RuntimeException(
                'Role not found.'
            );
        }

        $roleName = trim(
            (string) ($data['role_name'] ?? '')
        );

        $description = trim(
            (string) ($data['description'] ?? '')
        );

        if ($roleName === '') {
            throw new RuntimeException(
                'Role name is required.'
            );
        }

        $existing =
            $this->roles->findByName($roleName);

        if (
            $existing !== null
            && (int) $existing['id'] !== $id
        ) {
            throw new RuntimeException(
                'Role name already exists.'
            );
        }

        $this->roles->update(
            $id,
            [
                'role_name' => $roleName,
                'description' => $description,
                'active' => isset($data['active'])
                    ? 1
                    : 0,
                'updated_at' => date(
                    'Y-m-d H:i:s'
                )
            ]
        );
    }

    public function toggleStatus(int $id): void
    {
        $role = $this->roles->find($id);

        if ($role === null) {
            throw new RuntimeException(
                'Role not found.'
            );
        }

        if (
            $role['role_name'] === 'Administrator'
            && (int) $role['active'] === 1
        ) {
            throw new RuntimeException(
                'Administrator role cannot be deactivated.'
            );
        }

        $newStatus =
            (int) $role['active'] === 1
                ? 0
                : 1;

        $this->roles->setActive(
            $id,
            $newStatus
        );
    }
    public function permissions(): array
{
    return $this->roles
        ->activePermissions();
}

public function rolePermissionIds(
    int $roleId
): array {
    return $this->roles
        ->permissionIds($roleId);
}

public function savePermissions(
    int $roleId,
    array $permissionIds
): void {
    $role = $this->roles->find(
        $roleId
    );

    if ($role === null) {
        throw new RuntimeException(
            'Role not found.'
        );
    }

    $validPermissions =
        $this->roles->activePermissions();

    $validIds = array_map(
        static fn (
            array $permission
        ): int =>
            (int) $permission['id'],
        $validPermissions
    );

    $cleanIds = [];

    foreach ($permissionIds as $permissionId) {

        $permissionId =
            (int) $permissionId;

        if (
            in_array(
                $permissionId,
                $validIds,
                true
            )
        ) {
            $cleanIds[] =
                $permissionId;
        }
    }

    $cleanIds = array_values(
        array_unique($cleanIds)
    );

    $this->roles->syncPermissions(
        $roleId,
        $cleanIds
    );
}
}