<?php
/**
 * Permission Registry
 *
 * Manages permission definitions and their storage.
 *
 * @package FleekDash\Core
 * @since 2.3.0
 */

namespace FleekDash\Core;

defined('ABSPATH') || exit;

class PermissionRegistry {
    /**
     * Registry of all permissions
     */
    private static $registry = [];

    /**
     * Register a permission node
     *
     * @param array $permission Permission definition
     * @return void
     */
    public static function register(array $permission): void {
        $id = $permission['id'] ?? '';

        if (empty($id)) {
            throw new \InvalidArgumentException('Permission ID is required');
        }

        // Validate structure
        self::validate($permission);

        // Register
        self::$registry[$id] = $permission;

        // Link hierarchy
        if (!empty($permission['parent'])) {
            self::linkToParent($permission);
        }
    }

    /**
     * Register multiple permissions
     *
     * @param array $permissions Array of permission definitions
     * @return void
     */
    public static function registerMany(array $permissions): void {
        foreach ($permissions as $permission) {
            self::register($permission);
        }
    }

    /**
     * Get permission definition by ID
     *
     * @param string $id Permission ID
     * @return array|null Permission definition or null if not found
     */
    public static function get(string $id): ?array {
        return self::$registry[$id] ?? null;
    }

    /**
     * Check if permission exists
     *
     * @param string $id Permission ID
     * @return bool Whether permission exists
     */
    public static function has(string $id): bool {
        return isset(self::$registry[$id]);
    }

    /**
     * Get all registered permissions
     *
     * @return array All permissions
     */
    public static function getAll(): array {
        return self::$registry;
    }

    /**
     * Validate permission structure
     * @param array $permission Permission definition
     * @return void
     * @throws \InvalidArgumentException If invalid
     */
    private static function validate(array $permission): void {
        $id = $permission['id'] ?? '';

        if (empty($id)) {
            throw new \InvalidArgumentException('Permission ID is required');
        }

        if (!preg_match('/^[a-z0-9_.]+$/i', $id)) {
            throw new \InvalidArgumentException(
                "Invalid permission ID format: {$id}. Use only alphanumeric, dots, and underscores."
            );
        }

        if (empty($permission['label'])) {
            throw new \InvalidArgumentException("Permission label is required for: {$id}");
        }
    }

    /**
     * Link permission to parent
     *
     * @param array $permission Permission definition
     * @return void
     */
    private static function linkToParent(array $permission): void {
        $parent_id = $permission['parent'] ?? '';
        if (empty($parent_id) || !isset(self::$registry[$parent_id])) {
            return;
        }

        $parent = &self::$registry[$parent_id];
        if (!isset($parent['children'])) {
            $parent['children'] = [];
        }

        if (!in_array($permission['id'], $parent['children'], true)) {
            $parent['children'][] = $permission['id'];
        }
    }

    /**
     * Get registry statistics
     *
     * @return array Statistics
     */
    public static function getStats(): array {
        return [
            'total' => count(self::$registry),
            'roots' => count(array_filter(self::$registry, function($p) {
                return empty($p['parent']);
            })),
            'with_features' => count(array_filter(self::$registry, function($p) {
                return !empty($p['required_feature']);
            })),
            'with_capabilities' => count(array_filter(self::$registry, function($p) {
                return !empty($p['required_capability']);
            })),
            'admin_only' => count(array_filter(self::$registry, function($p) {
                return !empty($p['admin_only']);
            })),
        ];
    }

    /**
     * Clear all permissions
     *
     * @return void
     */
    public static function clear(): void {
        self::$registry = [];
    }
}
