<?php

declare(strict_types=1);

namespace WPUltimateSecurity\UltimateSecurity\Modules\TestMode;

use WPUltimateSecurity\UltimateSecurity\Support\Helpers\Utils;
use WPUltimateSecurity\UltimateSecurity\Infrastructure\Persistence\Repositories\TestModeSimulationRepository;

/**
 * Test Mode Service
 *
 * Manages test mode functionality for security features.
 * Uses TestModeSimulationRepository for data access.
 */
class TestModeService
{
    private static ?array $settings = null;
    private static ?bool $currentUserInTestMode = null;
    private static int $simulationCount = 0;

    /**
     * Repository instance (lazy-loaded singleton)
     *
     * @var TestModeSimulationRepository|null
     */
    private static ?TestModeSimulationRepository $repository = null;

    /**
     * Get the repository instance
     *
     * @return TestModeSimulationRepository
     */
    private static function getRepository(): TestModeSimulationRepository
    {
        if (self::$repository === null) {
            self::$repository = new TestModeSimulationRepository();
        }
        return self::$repository;
    }

    /**
     * Check if test mode is globally enabled
     */
    public static function isEnabled(): bool
    {
        $settings = self::getSettings();
        return (bool) ($settings['enabled'] ?? false);
    }

    /**
     * Primary method - Check if test mode applies to current request/user
     * Returns true if the action should be SIMULATED (not enforced)
     */
    public static function shouldSimulate(?int $userId = null): bool
    {
        if (!self::isEnabled()) {
            return false;
        }

        if ($userId === null && self::isEnabled()) {
            return true;
        }

        // Use cached result if available for current user
        if ($userId === null && self::$currentUserInTestMode !== null) {
            return self::$currentUserInTestMode;
        }

        $settings = self::getSettings();
        $targetUserId = $userId ?? get_current_user_id();

        // Anonymous users - test mode does NOT apply (security concern)
        if ($targetUserId === 0) {
            return false;
        }

        $user = get_userdata($targetUserId);
        if (!$user) {
            return false;
        }

        $userRoles = $user->roles;
        $affectedRoles = $settings['affected_roles'] ?? [];

        // Safety: exclude administrators unless explicitly disabled
        if (($settings['exclude_admins'] ?? true) &&
            (in_array('administrator', $userRoles, true) || user_can($targetUserId, 'manage_options'))) {
            return false;
        }

        $result = !empty(array_intersect($userRoles, $affectedRoles));

        if ($userId === null) {
            self::$currentUserInTestMode = $result;
        }

        return $result;
    }

    /**
     * Log a simulated security action
     */
    public static function logSimulation(
        string $module,
        string $action,
        string $reason,
        array $additionalContext = []
    ): bool {
        // Use repository's logSimulation method which handles all the context gathering
        $result = self::getRepository()->logSimulation(
            $module,
            $action,
            true, // would_have_blocked
            $reason,
            $additionalContext
        );

        return $result > 0;
    }

    /**
     * Get count of simulated blocks
     */
    public static function getSimulationCount(string $period = 'today'): int
    {
        global $wpdb;
        $tableName = $wpdb->prefix . 'ultimate_security_testmode_simulations';

        $dateCondition = '';
        switch ($period) {
            case 'today':
                $dateCondition = "WHERE DATE(created_at) = CURDATE()";
                break;
            case 'week':
                $dateCondition = "WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)";
                break;
            case 'month':
                $dateCondition = "WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)";
                break;
            case 'all':
            default:
                $dateCondition = '';
                break;
        }

        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        return (int) $wpdb->get_var("SELECT COUNT(*) FROM {$tableName} {$dateCondition}");
    }

    /**
     * Get simulations grouped by module
     */
    public static function getSimulationsByModule(string $period = 'today'): array
    {
        global $wpdb;
        $tableName = $wpdb->prefix . 'ultimate_security_testmode_simulations';

        $dateCondition = match ($period) {
            'today' => "WHERE DATE(created_at) = CURDATE()",
            'week' => "WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)",
            'month' => "WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)",
            default => ''
        };

        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $results = $wpdb->get_results(
            "SELECT module, COUNT(*) as count FROM {$tableName} {$dateCondition} GROUP BY module",
            ARRAY_A
        );

        $grouped = [];
        foreach ($results as $row) {
            $grouped[$row['module']] = (int) $row['count'];
        }

        return $grouped;
    }

    /**
     * Get recent simulation log entries
     */
    public static function getRecentSimulations(int $limit = 50, int $offset = 0): array
    {
        global $wpdb;
        $tableName = $wpdb->prefix . 'ultimate_security_testmode_simulations';

        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        return $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$tableName} ORDER BY created_at DESC LIMIT %d OFFSET %d",
            $limit,
            $offset
        ), ARRAY_A);
    }

    /**
     * Get test mode settings
     */
    public static function getSettings(): array
    {
        if (self::$settings === null) {
            $options = Utils::ultimate_security_get_option();
            self::$settings = $options['test_mode'] ?? [
                'enabled' => false,
                'affected_roles' => [],
                'exclude_admins' => true,
                'log_simulations' => true,
                'show_dashboard_notice' => true,
                'enabled_at' => null,
                'enabled_by' => null,
            ];
        }
        return self::$settings;
    }

    /**
     * Get allowed table names for truncation
     */
    private static function getAllowedTables(): array
    {
        global $wpdb;
        return [
            $wpdb->prefix . 'ultimate_security_testmode_simulations',
        ];
    }

    /**
     * Clear simulation logs
     */
    public static function clearSimulationLogs(): int
    {
        global $wpdb;
        $tableName = $wpdb->prefix . 'ultimate_security_testmode_simulations';

        // Validate table name against whitelist
        if (!in_array($tableName, self::getAllowedTables(), true)) {
            return 0;
        }

        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $tableName is validated against whitelist
        return (int) $wpdb->query("TRUNCATE TABLE {$tableName}");
    }

    /**
     * Reset cache (called when options are updated)
     */
    public static function resetCache(): void
    {
        self::$settings = null;
        self::$currentUserInTestMode = null;
        self::$simulationCount = 0;
    }

    /**
     * Get available WordPress roles (excluding administrator by default)
     */
    public static function getAvailableRoles(bool $includeAdmin = false): array
    {
        $roles = wp_roles()->roles;
        $available = [];
        foreach ($roles as $slug => $role) {
            if (!$includeAdmin && $slug === 'administrator') {
                continue;
            }
            $available[$slug] = translate_user_role($role['name']);
        }
        return $available;
    }

    /**
     * Get total count of simulation logs
     */
    public static function getTotalSimulationCount(): int
    {
        global $wpdb;
        $tableName = $wpdb->prefix . 'ultimate_security_testmode_simulations';

        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        return (int) $wpdb->get_var("SELECT COUNT(*) FROM {$tableName}");
    }
}
