<?php
/**
 * Advanced Anti-Bot Protection - Server Side
 * Validates client-side protection tokens and implements rate limiting
 */

// Prevent direct access
if (!defined('APP_ACCESS')) {
    die('Direct access not permitted');
}

class AdvancedProtection {
    
    private $clientIP;
    private $rateLimitFile;
    private $honeypotFile;
    private $maxRequestsPerMinute = 10;
    private $maxRequestsPerHour = 100;
    private $blockDuration = 3600; // 1 hour
    
    public function __construct() {
        $this->clientIP = $this->getClientIP();
        $this->rateLimitFile = LOGS_PATH . '/rate_limit.json';
        $this->honeypotFile = LOGS_PATH . '/honeypot.log';
    }
    
    /**
     * Get real client IP
     */
    private function getClientIP() {
        $ip = $_SERVER['REMOTE_ADDR'];
        
        if (!empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
            $ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ip = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
        } elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        }
        
        return trim($ip);
    }
    
    /**
     * Check if IP is localhost
     */
    private function isLocalhost() {
        $localIPs = ['127.0.0.1', '::1', 'localhost'];
        
        if (in_array($this->clientIP, $localIPs)) {
            return true;
        }
        
        if (strpos($this->clientIP, '192.168.') === 0 ||
            strpos($this->clientIP, '10.') === 0 ||
            strpos($this->clientIP, '172.16.') === 0) {
            return true;
        }
        
        return false;
    }
    
    /**
     * RATE LIMITING - Check if IP is making too many requests
     */
    public function checkRateLimit() {
        // Always allow localhost
        if ($this->isLocalhost()) {
            return true;
        }
        
        $data = $this->loadRateLimitData();
        $now = time();
        $ip = $this->clientIP;
        
        // Initialize IP data if not exists
        if (!isset($data[$ip])) {
            $data[$ip] = [
                'requests' => [],
                'blocked_until' => 0
            ];
        }
        
        // Check if IP is currently blocked
        if ($data[$ip]['blocked_until'] > $now) {
            $this->logBlock('Rate Limit Exceeded - Still Blocked');
            $this->blockAccess('Too many requests. Please try again later.');
            return false;
        }
        
        // Clean old requests (older than 1 hour)
        $data[$ip]['requests'] = array_filter($data[$ip]['requests'], function($timestamp) use ($now) {
            return ($now - $timestamp) < 3600;
        });
        
        // Add current request
        $data[$ip]['requests'][] = $now;
        
        // Count requests in last minute
        $requestsLastMinute = count(array_filter($data[$ip]['requests'], function($timestamp) use ($now) {
            return ($now - $timestamp) < 60;
        }));
        
        // Count requests in last hour
        $requestsLastHour = count($data[$ip]['requests']);
        
        // Check limits
        if ($requestsLastMinute > $this->maxRequestsPerMinute) {
            $data[$ip]['blocked_until'] = $now + $this->blockDuration;
            $this->saveRateLimitData($data);
            $this->logBlock('Rate Limit Exceeded - Per Minute');
            $this->blockAccess('Too many requests per minute. Blocked for 1 hour.');
            return false;
        }
        
        if ($requestsLastHour > $this->maxRequestsPerHour) {
            $data[$ip]['blocked_until'] = $now + $this->blockDuration;
            $this->saveRateLimitData($data);
            $this->logBlock('Rate Limit Exceeded - Per Hour');
            $this->blockAccess('Too many requests per hour. Blocked for 1 hour.');
            return false;
        }
        
        // Save updated data
        $this->saveRateLimitData($data);
        return true;
    }
    
    /**
     * Load rate limit data
     */
    private function loadRateLimitData() {
        if (!file_exists($this->rateLimitFile)) {
            return [];
        }
        
        $content = file_get_contents($this->rateLimitFile);
        $data = json_decode($content, true);
        
        return is_array($data) ? $data : [];
    }
    
    /**
     * Save rate limit data
     */
    private function saveRateLimitData($data) {
        // Clean old data (IPs not seen in 24 hours)
        $now = time();
        foreach ($data as $ip => $info) {
            if (empty($info['requests'])) {
                unset($data[$ip]);
                continue;
            }
            
            $lastRequest = max($info['requests']);
            if (($now - $lastRequest) > 86400) {
                unset($data[$ip]);
            }
        }
        
        file_put_contents($this->rateLimitFile, json_encode($data), LOCK_EX);
    }
    
    /**
     * VALIDATE ANTI-BOT TOKEN from JavaScript
     */
    public function validateToken() {
        // Always allow localhost
        if ($this->isLocalhost()) {
            return true;
        }
        
        // Check for token in cookie or POST
        $token = null;
        
        if (isset($_COOKIE['_abp'])) {
            $token = $_COOKIE['_abp'];
        } elseif (isset($_POST['_abp_token'])) {
            $token = $_POST['_abp_token'];
        }
        
        // No token = suspicious (but give one chance for first visit)
        if (!$token) {
            if (!isset($_SESSION['_abp_warning'])) {
                $_SESSION['_abp_warning'] = true;
                return true; // First visit, allow but warn
            }
            
            $this->logBlock('No Anti-Bot Token');
            return false;
        }
        
        // Decode and validate token
        try {
            $decoded = base64_decode($token);
            $data = json_decode($decoded, true);
            
            if (!$data || !is_array($data)) {
                $this->logBlock('Invalid Token Format');
                return false;
            }
            
            // Check bot score
            if (isset($data['bs']) && $data['bs'] > 50) {
                $this->logBlock('High Bot Score: ' . $data['bs']);
                return false;
            }
            
            // Check for minimum interaction
            if (isset($data['t']) && $data['t'] < 1000) {
                $this->logBlock('Too Fast: ' . $data['t'] . 'ms');
                return false;
            }
            
            // Check for mouse movements
            if (isset($data['mm']) && $data['mm'] === 0 && isset($data['t']) && $data['t'] > 3000) {
                $this->logBlock('No Mouse Movement');
                return false;
            }
            
            // Token is valid
            return true;
            
        } catch (Exception $e) {
            $this->logBlock('Token Validation Error');
            return false;
        }
    }
    
    /**
     * CHECK HONEYPOT FIELDS
     * Honeypot fields are invisible to humans but bots fill them
     */
    public function checkHoneypot() {
        // Always allow localhost
        if ($this->isLocalhost()) {
            return true;
        }
        
        $honeypotFields = ['email_confirm', 'website', 'phone_number', 'company'];
        
        foreach ($honeypotFields as $field) {
            if (isset($_POST[$field]) && !empty($_POST[$field])) {
                $this->logHoneypot($field, $_POST[$field]);
                $this->logBlock('Honeypot Field Filled: ' . $field);
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * CHECK SESSION VALIDITY
     */
    public function checkSession() {
        // Always allow localhost
        if ($this->isLocalhost()) {
            return true;
        }
        
        // Start session if not started
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }
        
        // Check if session has required markers
        if (!isset($_SESSION['_init_time'])) {
            $_SESSION['_init_time'] = time();
            $_SESSION['_init_ip'] = $this->clientIP;
            $_SESSION['_init_ua'] = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
        }
        
        // Check for session hijacking
        if ($_SESSION['_init_ip'] !== $this->clientIP) {
            $this->logBlock('Session IP Mismatch');
            return false;
        }
        
        $currentUA = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
        if ($_SESSION['_init_ua'] !== $currentUA) {
            $this->logBlock('Session UA Mismatch');
            return false;
        }
        
        return true;
    }
    
    /**
     * CHECK REFERRER
     */
    public function checkReferrer() {
        // Always allow localhost
        if ($this->isLocalhost()) {
            return true;
        }
        
        // For POST requests, check referrer
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
            
            // No referrer on POST = suspicious
            if (empty($referrer)) {
                $this->logBlock('No Referrer on POST');
                return false;
            }
            
            // Referrer should be from same domain
            $host = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
            if (!empty($host) && strpos($referrer, $host) === false) {
                $this->logBlock('External Referrer on POST');
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * CHECK COOKIES
     */
    public function checkCookies() {
        // Always allow localhost
        if ($this->isLocalhost()) {
            return true;
        }
        
        // Set a test cookie
        if (!isset($_COOKIE['_test'])) {
            setcookie('_test', '1', time() + 3600, '/');
            $_SESSION['_cookie_test'] = true;
            return true;
        }
        
        // If we set the cookie but it's not there, cookies are disabled
        if (isset($_SESSION['_cookie_test']) && !isset($_COOKIE['_test'])) {
            $this->logBlock('Cookies Disabled');
            return false;
        }
        
        return true;
    }
    
    /**
     * CHECK BLACKLIST - Check if IP is banned
     */
    public function checkBlacklist() {
        // Always allow localhost
        if ($this->isLocalhost()) {
            return true;
        }
        
        $blacklistFile = BASE_PATH . '/Panel/blacklist.txt';
        
        if (file_exists($blacklistFile)) {
            $content = file_get_contents($blacklistFile);
            $bannedIPs = array_filter(array_map('trim', explode("\n", $content)));
            
            if (in_array($this->clientIP, $bannedIPs)) {
                $this->logBlock('IP is in blacklist');
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * COMPREHENSIVE CHECK - Run all protections
     */
    public function runAllChecks() {
        // Always allow localhost
        if ($this->isLocalhost()) {
            return true;
        }
        
        // 0. Check blacklist first
        if (!$this->checkBlacklist()) {
            $this->blockAccess('Access denied - IP banned');
            return false;
        }
        
        // 1. Rate limiting
        if (!$this->checkRateLimit()) {
            return false;
        }
        
        // 2. Session validation
        if (!$this->checkSession()) {
            $this->blockAccess('Session validation failed');
            return false;
        }
        
        // 3. Cookie check
        if (!$this->checkCookies()) {
            $this->blockAccess('Cookies must be enabled');
            return false;
        }
        
        // 4. Referrer check
        if (!$this->checkReferrer()) {
            $this->blockAccess('Invalid referrer');
            return false;
        }
        
        // 5. Honeypot check (only on POST)
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            if (!$this->checkHoneypot()) {
                $this->blockAccess('Security check failed');
                return false;
            }
            
            // 6. Token validation (only on POST)
            if (!$this->validateToken()) {
                $this->blockAccess('Security validation failed');
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * Log honeypot trigger
     */
    private function logHoneypot($field, $value) {
        $logMessage = sprintf(
            "[%s] HONEYPOT - IP: %s | Field: %s | Value: %s | UA: %s\n",
            date('Y-m-d H:i:s'),
            $this->clientIP,
            $field,
            substr($value, 0, 50),
            isset($_SERVER['HTTP_USER_AGENT']) ? substr($_SERVER['HTTP_USER_AGENT'], 0, 100) : 'Unknown'
        );
        
        @file_put_contents($this->honeypotFile, $logMessage, FILE_APPEND);
    }
    
    /**
     * Log block
     */
    private function logBlock($reason) {
        if (defined('BOTS_LOG_FILE')) {
            $logMessage = sprintf(
                "[%s] ADVANCED BLOCK - IP: %s | Reason: %s | UA: %s\n",
                date('Y-m-d H:i:s'),
                $this->clientIP,
                $reason,
                isset($_SERVER['HTTP_USER_AGENT']) ? substr($_SERVER['HTTP_USER_AGENT'], 0, 100) : 'Unknown'
            );
            
            @file_put_contents(BOTS_LOG_FILE, $logMessage, FILE_APPEND);
        }
    }
    
    /**
     * Block access
     */
    private function blockAccess($message = 'Access denied') {
        header('HTTP/1.1 403 Forbidden');
        header('Location: https://www.spotify.com');
        echo '<!DOCTYPE html><html><head><title>Access Denied</title></head><body>';
        echo '<h1>403 Forbidden</h1>';
        echo '<p>' . htmlspecialchars($message) . '</p>';
        echo '</body></html>';
        exit;
    }
}

?>
