<?php

declare(strict_types=1);

namespace App\Models;

use App\Core\BaseModel;

final class PermissionModel extends BaseModel
{
    protected string $table = 'permissions';
    protected array $fillable = ['module', 'action', 'slug', 'description'];
    protected bool $timestamps = false;
    protected bool $softDeletes = false;
    protected bool $auditStamps = false;

    public function all(array $where = [], string $orderBy = 'module ASC, action ASC', ?int $limit = null): array
    {
        return parent::all($where, $orderBy, $limit);
    }

    /** Builds the full permission matrix: every role x every module, with the effective level ('full'/'partial'/'none'). */
    public function matrix(): array
    {
        $permissions = $this->all();
        $roles = $this->db->query('SELECT id, name, slug FROM roles ORDER BY name')->fetchAll();

        $grants = $this->db->query(
            'SELECT rp.role_id, p.slug FROM role_permissions rp JOIN permissions p ON p.id = rp.permission_id'
        )->fetchAll();

        $grantMap = [];
        foreach ($grants as $grant) {
            $grantMap[$grant['role_id']][$grant['slug']] = true;
        }

        $modules = [];
        $permissionIds = [];
        foreach ($permissions as $permission) {
            $modules[$permission['module']]['actions'][] = $permission['action'];
            $modules[$permission['module']]['slugs'][] = $permission['slug'];
            $permissionIds[$permission['slug']] = (int) $permission['id'];
        }

        return ['roles' => $roles, 'modules' => $modules, 'grants' => $grantMap, 'permission_ids' => $permissionIds];
    }

    /** Replaces a role's entire permission set with the given list of permission ids — used by the Permission Matrix save action. */
    public function syncRolePermissions(int $roleId, array $permissionIds): void
    {
        $this->db->prepare('DELETE FROM role_permissions WHERE role_id = :role_id')->execute(['role_id' => $roleId]);

        if ($permissionIds === []) {
            return;
        }

        $stmt = $this->db->prepare(
            'INSERT INTO role_permissions (role_id, permission_id, created_at) VALUES (:role_id, :permission_id, NOW())'
        );

        foreach (array_unique(array_map('intval', $permissionIds)) as $permissionId) {
            $stmt->execute(['role_id' => $roleId, 'permission_id' => $permissionId]);
        }
    }
}
