<?php
/**
 * Permission System Bootstrap
 *
 * Initializes the permission system, registers definitions,
 * sets up REST API endpoints, and injects SSR data.
 *
 * @package FleekDash\Core
 */

namespace FleekDash\Core;

use FleekDash\API\PermissionController;
use FleekDash\API\PermissionOverrideController;
use FleekDash\API\PermissionRequestController;
use FleekDash\Core\PermissionOverrideManager;

class PermissionBootstrap {
    /**
     * Whether the system is initialized
     */
    private static bool $initialized = false;

    /**
     * Initialize permission system
     *
     * Should be called once during plugin initialization.
     *
     * @return void
     */
    public static function init(): void {
        if (self::$initialized) {
            return;
        }

        // Register all permission definitions
        add_action('init', [self::class, 'registerPermissions'], 5);

        // Register REST API endpoints
        add_action('rest_api_init', [self::class, 'registerRestRoutes']);

        // Inject SSR data for frontend.
        // Priority 6 — runs after FeaturesManager::inject_features (priority 5),
        // ensuring the features transient is warm when checkFeature() is called.
        if (is_admin()) {
            add_action('admin_enqueue_scripts', [self::class, 'injectSSRData'], 6);
        }

        // Setup cache invalidation hooks
        self::setupCacheInvalidation();

        // Setup override expiration cron
        add_action('init', [self::class, 'scheduleOverrideCleanup']);
        add_action('fleekdash_cleanup_expired_overrides', [PermissionOverrideManager::class, 'cleanupExpired']);

        self::$initialized = true;
    }

    /**
     * Register all permission definitions
     *
     * @return void
     */
    public static function registerPermissions(): void {
        PermissionDefinitions::register();
    }

    /**
     * Register REST API routes
     *
     * @return void
     */
    public static function registerRestRoutes(): void {
        self::ensureOverrideTablesExist();

        // Register override routes BEFORE PermissionController so GET /permissions/overrides
        // is matched by the list endpoint, not by /permissions/(?P<id>...) with id=overrides.
        $override_controller = new PermissionOverrideController();
        $override_controller->register_routes();

        $request_controller = new PermissionRequestController();
        $request_controller->register_routes();

        $controller = new PermissionController();
        $controller->register_routes();
    }

    /**
     * Ensure permission override tables exist (run migration if missing).
     * Avoids 500 errors when overrides feature is used before wp fleekdash migration:run.
     *
     * @return void
     */
    private static function ensureOverrideTablesExist(): void {
        global $wpdb;
        $table = $wpdb->prefix . 'fleekdash_user_permission_overrides';

        if ($wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table)) === $table) {
            return;
        }

        $migration_file = FLEEKDASH_DIR . 'database/Migrations/2026_03_18_000001_create_user_override_tables.php';
        if (!is_readable($migration_file)) {
            return;
        }

        try {
            $migration = require_once $migration_file;
            if (is_object($migration) && method_exists($migration, 'up')) {
                $migration->up();
            }
        } catch (\Throwable $e) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('[FleekDash] Permission override tables migration failed: ' . $e->getMessage());
            }
        }
    }

    /**
     * Inject SSR permission data
     *
     * @param string $hook_suffix Current admin screen basename — passed by WordPress to admin_enqueue_scripts.
     * @return void
     */
    public static function injectSSRData(string $hook_suffix = ''): void {
        PermissionManager::injectSSRData($hook_suffix);
    }

    /**
     * Setup cache invalidation hooks
     *
     * @return void
     */
    private static function setupCacheInvalidation(): void {
        // Invalidate when user role changes
        add_action('set_user_role', [self::class, 'invalidateUserCache'], 10, 2);
        add_action('add_user_role', [self::class, 'invalidateUserCache'], 10, 2);
        add_action('remove_user_role', [self::class, 'invalidateUserCache'], 10, 2);

        // Invalidate when role capabilities change
        add_action('added_role_capability', [self::class, 'invalidateRoleCache'], 10, 2);
        add_action('removed_role_capability', [self::class, 'invalidateRoleCache'], 10, 2);

        // Invalidate when license changes
        add_action('fleekdash_license_activated', [self::class, 'invalidateAllCache']);
        add_action('fleekdash_license_deactivated', [self::class, 'invalidateAllCache']);
        add_action('fleekdash_license_updated', [self::class, 'invalidateAllCache']);

        // Invalidate when features change
        add_action('fleekdash_features_updated', [self::class, 'invalidateAllCache']);
    }

    /**
     * Schedule daily override expiration cleanup
     */
    public static function scheduleOverrideCleanup(): void {
        if (!wp_next_scheduled('fleekdash_cleanup_expired_overrides')) {
            wp_schedule_event(time(), 'daily', 'fleekdash_cleanup_expired_overrides');
        }
    }

    /**
     * Invalidate cache for a specific user
     *
     * @param int $user_id User ID
     * @param string $role Role name (required by WordPress hook signature)
     * @return void
     */
    // NOSONAR S1172 - $role required by set_user_role hook signature
    public static function invalidateUserCache(int $user_id, string $role = ''): void { // NOSONAR S1172
        PermissionManager::clearCache(null, $user_id);
        PermissionManager::clearUserOverridesCache($user_id);
        // So REST AuthMiddleware::check() does not serve a stale "authenticated" result for up to CACHE_TTL after role changes.
        AuthMiddleware::clearUserCache($user_id);
    }

    /**
     * Invalidate cache for a specific role
     *
     * @param string $role Role name
     * @param string $capability Capability name (required by WordPress hook signature)
     * @return void
     */
    // NOSONAR S1172 - $capability required by added_role_capability hook signature
    public static function invalidateRoleCache(string $role, string $capability = ''): void { // NOSONAR S1172
        // Get all users with this role and invalidate their cache
        $users = \get_users(['role' => $role, 'fields' => 'ID']);
        foreach ($users as $user_id) {
            PermissionManager::clearCache(null, $user_id);
            AuthMiddleware::clearUserCache((int) $user_id);
        }
    }

    /**
     * Invalidate all permission caches
     *
     * @return void
     */
    public static function invalidateAllCache(): void {
        PermissionManager::clearCache();
        AuthMiddleware::clearAllCache();
    }
}
