<?php

declare(strict_types=1);

namespace App\Repositories;

use PDO;

final class RoleRepository
{
    public function __construct(private PDO $pdo)
    {
    }

    public function create(string $name): int
    {
        $st = $this->pdo->prepare("INSERT INTO roles (name, is_system) VALUES (?,0)");
        $st->execute([$name]);
        return (int)$this->pdo->lastInsertId();
    }

    public function allRoles(): array
    {
        return $this->pdo->query("SELECT id, name, is_system FROM roles ORDER BY is_system DESC, name")->fetchAll() ?: [];
    }

    public function allPermissionsGroupedByModule(): array
    {
        $allPerms = $this->pdo->query("SELECT id, code, name, module FROM permissions ORDER BY module, name")->fetchAll() ?: [];
        $permsByModule = [];
        foreach ($allPerms as $p) {
            $permsByModule[$p['module']][] = $p;
        }
        return $permsByModule;
    }


    public function roleNameExists(string $name, ?int $excludeId = null): bool
    {
        if ($excludeId !== null && $excludeId > 0) {
            $st = $this->pdo->prepare("SELECT COUNT(*) FROM roles WHERE name = ? AND id <> ?");
            $st->execute([$name, $excludeId]);
            return (int)$st->fetchColumn() > 0;
        }

        $st = $this->pdo->prepare("SELECT COUNT(*) FROM roles WHERE name = ?");
        $st->execute([$name]);
        return (int)$st->fetchColumn() > 0;
    }

    public function findRole(int $roleId): array|false
    {
        $st = $this->pdo->prepare("SELECT id, name, is_system FROM roles WHERE id=?");
        $st->execute([$roleId]);
        return $st->fetch();
    }

    public function assignedPermissionCodes(int $roleId): array
    {
        $st = $this->pdo->prepare("SELECT p.code FROM role_permissions rp JOIN permissions p ON p.id=rp.permission_id WHERE rp.role_id=?");
        $st->execute([$roleId]);
        $assigned = [];
        foreach (($st->fetchAll() ?: []) as $r) {
            $assigned[$r['code']] = true;
        }
        return $assigned;
    }

    public function replacePermissions(int $roleId, array $codes): void
    {
        $this->pdo->prepare("DELETE FROM role_permissions WHERE role_id=?")->execute([$roleId]);

        if (!$codes) {
            return;
        }

        $in = implode(',', array_fill(0, count($codes), '?'));
        $st = $this->pdo->prepare("SELECT id, code FROM permissions WHERE code IN ($in)");
        $st->execute(array_values($codes));
        $rows = $st->fetchAll() ?: [];
        $ins = $this->pdo->prepare("INSERT INTO role_permissions (role_id, permission_id) VALUES (?,?)");
        foreach ($rows as $r) {
            $ins->execute([$roleId, (int)$r['id']]);
        }
    }

    public function isSystemRole(int $roleId): bool
    {
        $st = $this->pdo->prepare("SELECT is_system FROM roles WHERE id=?");
        $st->execute([$roleId]);
        return (int)($st->fetchColumn() ?: 0) === 1;
    }

    public function delete(int $roleId): void
    {
        $this->pdo->prepare("DELETE FROM roles WHERE id=?")->execute([$roleId]);
    }
}
