<?php
/**
 * Trusted Service Verification Layer
 * 
 * Enterprise-grade verification for known infrastructure providers.
 * Uses ASN, CIDR, UA pattern matching, and behavioral profiling.
 *
 * @package BotFend\Security
 * @version 5.1.0
 */

namespace BotFend\Security;

use BotFend\Utilities\Utilities;
use BotFend\Core\Config;

defined('ABSPATH') || exit;

class TrustedServiceVerifier {
    
    /** Trust levels */
    const TRUST_NONE     = 0;
    const TRUST_LOW      = 25;
    const TRUST_MEDIUM   = 50;
    const TRUST_HIGH     = 75;
    const TRUST_VERIFIED = 100;
    
    /** @var Utilities */
    private $utilities;
    
    /** @var Config */
    private $config;
    
    /** @var array Trust cache */
    private static $trust_cache = [];
    
    /** @var array Service profiles */
    private $service_profiles = [];
    
    public function __construct(Utilities $utilities, Config $config) {
        $this->utilities = $utilities;
        $this->config = $config;
        $this->load_service_profiles();
    }
    
    /**
     * Load service profiles
     */
    private function load_service_profiles(): void {
        $this->service_profiles = [
            'automattic' => [
                'name'            => 'Automattic',
                'asn'             => [2635],
                'cidrs'           => \BotFend\Utilities\Utilities::AUTOMATTIC_IPS,
                'ua_patterns'     => ['photon', 'jetpack', 'wordpress\.com', 'wp\.com'],
                'rdns_patterns'   => ['wordpress.com', 'wp.com', 'automattic.com'],
                'allowed_methods' => ['GET', 'HEAD'],
                'allowed_paths'   => ['wp-content/uploads'],
                'trust_level'     => self::TRUST_HIGH,
            ],
            'google' => [
                'name'            => 'Google',
                'asn'             => [15169, 36040],
                'cidrs'           => \BotFend\Utilities\Utilities::GOOGLE_IPS,
                'ua_patterns'     => ['googlebot', 'google-inspectiontool', 'mediapartners-google', 'adsbot-google'],
                'rdns_patterns'   => ['googlebot.com', 'google.com'],
                'allowed_methods' => ['GET', 'HEAD'],
                'trust_level'     => self::TRUST_VERIFIED,
            ],
            'cloudflare' => [
                'name'            => 'Cloudflare',
                'asn'             => [13335, 209242],
                'ua_patterns'     => ['cloudflare'],
                'rdns_patterns'   => ['cloudflare.com'],
                'allowed_methods' => ['GET', 'HEAD', 'POST'],
                'trust_level'     => self::TRUST_HIGH,
            ],
            'microsoft' => [
                'name'            => 'Microsoft',
                'asn'             => [8075, 3598, 6584, 8068, 8069],
                'cidrs'           => \BotFend\Utilities\Utilities::BING_IPS,
                'ua_patterns'     => ['bingbot', 'msnbot', 'bingpreview'],
                'rdns_patterns'   => ['search.msn.com'],
                'allowed_methods' => ['GET', 'HEAD'],
                'trust_level'     => self::TRUST_VERIFIED,
            ],
            'meta' => [
                'name'            => 'Meta',
                'asn'             => [32934, 54115],
                'cidrs'           => \BotFend\Utilities\Utilities::FACEBOOK_IPS,
                'ua_patterns'     => ['facebookexternalhit', 'meta-externalagent'],
                'rdns_patterns'   => ['facebook.com', 'fb.com'],
                'allowed_methods' => ['GET', 'HEAD'],
                'trust_level'     => self::TRUST_HIGH,
            ],
            'slack' => [
                'name'            => 'Slack',
                'asn'             => [394505],
                'ua_patterns'     => ['slackbot', 'slack-imgproxy'],
                'rdns_patterns'   => ['slack.com'],
                'allowed_methods' => ['GET', 'HEAD'],
                'trust_level'     => self::TRUST_MEDIUM,
            ],
            'discord' => [
                'name'            => 'Discord',
                'asn'             => [398441],
                'ua_patterns'     => ['discordbot'],
                'rdns_patterns'   => ['discord.com'],
                'allowed_methods' => ['GET', 'HEAD'],
                'trust_level'     => self::TRUST_MEDIUM,
            ],
        ];
    }
    
    /**
     * Verify a request against trusted services
     *
     * @param string $ip      Client IP
     * @param string $ua      User agent
     * @param array  $server  $_SERVER superglobal
     * @return array [trust_level, service_name, verified, reason]
     */
    public function verify(string $ip, string $ua, array $server): array {
        $cache_key = 'trust_' . md5($ip . $ua);
        
        if (isset(self::$trust_cache[$cache_key])) {
            return self::$trust_cache[$cache_key];
        }
        
        $result = [
            'trust_level'  => self::TRUST_NONE,
            'service_name' => '',
            'verified'     => false,
            'reason'       => '',
        ];
        
        // 1. Extract claimed service from UA
        $claimed_service = $this->utilities->extract_crawler_from_ua($ua);
        if (!$claimed_service) {
            return $this->cache_result($cache_key, $result);
        }
        
        // 2. Check if service is in our profiles
        if (!isset($this->service_profiles[$claimed_service])) {
            return $this->cache_result($cache_key, $result);
        }
        
        $profile = $this->service_profiles[$claimed_service];
        
        // 3. Validate CIDR range
        $cidr_verified = false;
        if (isset($profile['cidrs'])) {
            foreach ($profile['cidrs'] as $range) {
                if ($this->utilities->ip_in_range($ip, $range)) {
                    $cidr_verified = true;
                    break;
                }
            }
        }
        
        // 4. Validate reverse DNS (if enabled)
        $rdns_verified = false;
        if ($this->config->get_bool('enable_reverse_dns', false)) {
            $rdns_verified = $this->utilities->verify_reverse_dns($ip, $claimed_service);
        } else {
            $rdns_verified = $cidr_verified; // Fallback to CIDR only
        }
        
        // 5. Validate request method
        $method_ok = in_array($server['REQUEST_METHOD'] ?? 'GET', $profile['allowed_methods'] ?? ['GET', 'HEAD'], true);
        
        // 6. Calculate trust score
        $score = 0;
        if ($cidr_verified) $score += 40;
        if ($rdns_verified) $score += 35;
        if ($method_ok)      $score += 25;
        
        $trust_level = match(true) {
            $score >= 80 => self::TRUST_VERIFIED,
            $score >= 60 => self::TRUST_HIGH,
            $score >= 40 => self::TRUST_MEDIUM,
            $score >= 20 => self::TRUST_LOW,
            default      => self::TRUST_NONE,
        };
        
        $result = [
            'trust_level'  => $trust_level,
            'service_name' => $claimed_service,
            'verified'     => $trust_level >= self::TRUST_HIGH,
            'reason'       => sprintf(
                'CIDR: %s, rDNS: %s, Method: %s, Score: %d',
                $cidr_verified ? 'yes' : 'no',
                $rdns_verified ? 'yes' : 'no',
                $method_ok ? 'ok' : 'blocked',
                $score
            ),
        ];
        
        return $this->cache_result($cache_key, $result);
    }
    
    /**
     * Get trust level for a service
     *
     * @param string $service_name
     * @return int
     */
    public function get_service_trust_level(string $service_name): int {
        return $this->service_profiles[$service_name]['trust_level'] ?? self::TRUST_NONE;
    }
    
    /**
     * Check if request method is allowed for service
     *
     * @param string $service_name
     * @param string $method
     * @return bool
     */
    public function is_method_allowed(string $service_name, string $method): bool {
        if (!isset($this->service_profiles[$service_name])) {
            return false;
        }
        return in_array($method, $this->service_profiles[$service_name]['allowed_methods'] ?? ['GET', 'HEAD'], true);
    }
    
    /**
     * Cache verification result
     */
    private function cache_result(string $key, array $result): array {
        if (count(self::$trust_cache) >= 500) {
            self::$trust_cache = array_slice(self::$trust_cache, 100, null, true);
        }
        self::$trust_cache[$key] = $result;
        return $result;
    }
    
    /**
     * Clear trust cache
     */
    public static function clear_cache(): void {
        self::$trust_cache = [];
    }
}