<?php
/**
 * Permission Middleware
 *
 * Enhanced authentication middleware with unified permission validation.
 * Combines role-based (capabilities) and feature-based (license) checks.
 *
 * @package FleekDash\Core
 */

namespace FleekDash\Core;

class PermissionMiddleware {
    /**
     * Check permission with authentication
     *
     * @param string $permission_id Permission ID to check
     * @return array Result with 'authenticated', 'allowed', 'reason', and 'metadata'
     */
    public static function check(string $permission_id): array {
        // 1. Basic auth check
        if (!\is_user_logged_in()) {
            return [
                'authenticated' => false,
                'allowed' => false,
                'reason' => 'not_authenticated',
                'metadata' => PermissionManager::createEmptyMetadata(),
            ];
        }

        // 2. Permission check (includes user overrides)
        $permission_result = PermissionManager::checkWithOverride($permission_id);

        return array_merge(
            ['authenticated' => true],
            $permission_result
        );
    }

    /**
     * Check permission with graceful fallback
     *
     * Returns formatted API response with fallback data when denied.
     *
     * @param string $permission_id Permission ID to check
     * @param array $fallback_data Data to return when permission denied
     * @return array API response array
     */
    public static function checkWithFallback(
        string $permission_id,
        array $fallback_data = []
    ): array {
        $result = self::check($permission_id);

        if (!$result['allowed']) {
            return [
                'success' => false,
                'message' => 'Permission denied',
                'reason' => $result['reason'] ?? 'unknown',
                'fallback_data' => $fallback_data,
                'metadata' => $result['metadata'] ?? [],
            ];
        }

        return [
            'success' => true,
            'allowed' => true,
            'metadata' => $result['metadata'] ?? [],
        ];
    }

    /**
     * Check multiple permissions at once
     *
     * @param array $permission_ids Array of permission IDs
     * @return array Map of permission ID to result
     */
    public static function checkMany(array $permission_ids): array {
        $results = [];

        foreach ($permission_ids as $id) {
            $results[$id] = PermissionManager::checkWithOverride($id);
        }

        return $results;
    }

    /**
     * Require permission (throw exception if denied)
     *
     * @param string $permission_id Permission ID to require
     * @param string|null $message Custom error message
     * @return void
     * @throws \WP_Error If permission denied
     */
    public static function require(string $permission_id, ?string $message = null): void {
        $result = self::check($permission_id);

        if (!$result['allowed']) {
            $default_message = self::getReasonMessage($result['reason'] ?? 'unknown');
            throw new \WP_Error(
                'permission_denied',
                $message ?? $default_message,
                [
                    'status' => 403,
                    'permission' => $permission_id,
                    'reason' => $result['reason'],
                    'metadata' => $result['metadata'] ?? [],
                ]
            );
        }
    }

    /**
     * Get user-friendly message for permission denial reason
     *
     * @param string $reason Denial reason
     * @return string User-friendly message
     */
    private static function getReasonMessage(string $reason): string {
        $messages = [
            'not_authenticated' => 'You must be logged in to access this.',
            'feature_missing' => 'Your plan does not include this feature. Please upgrade.',
            'capability_missing' => 'You do not have permission to access this.',
            'parent_blocked' => 'Parent permission is blocked.',
            'admin_only' => 'Only administrators can access this.',
            'not_found' => 'Permission not found.',
            'override_denied' => 'Your access was explicitly blocked by an administrator.',
        ];

        return $messages[$reason] ?? 'Access denied.';
    }

    /**
     * Create permission callback for REST routes
     *
     * Returns a callback function that checks the specified permission.
     *
     * @param string $permission_id Permission ID to check
     * @return callable Permission callback
     */
    public static function createCallback(string $permission_id): callable {
        return function() use ($permission_id) {
            $result = self::check($permission_id);
            return $result['allowed'];
        };
    }

    /**
     * Middleware for WordPress hooks/filters
     *
     * Executes callback only if permission is granted.
     *
     * @param string $permission_id Permission ID to check
     * @param callable $callback Callback to execute if allowed
     * @return callable Wrapped callback
     */
    public static function wrap(string $permission_id, callable $callback): callable {
        return function(...$args) use ($permission_id, $callback) {
            $result = self::check($permission_id);

            if (!$result['allowed']) {
                return null;
            }

            return call_user_func_array($callback, $args);
        };
    }

    /**
     * Check if current user has permission (simple boolean)
     *
     * @param string $permission_id Permission ID to check
     * @return bool Whether user has permission
     */
    public static function can(string $permission_id): bool {
        $result = self::check($permission_id);
        return $result['allowed'] === true;
    }

    /**
     * Check if current user does NOT have permission (simple boolean)
     *
     * @param string $permission_id Permission ID to check
     * @return bool Whether user lacks permission
     */
    public static function cannot(string $permission_id): bool {
        return !self::can($permission_id);
    }
}
