<?php

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once 'dashboard/config.php';
require_once 'blacklists.php';

class BotDetector_2 {
    // Properties
    public    $trustedISPs            = [];
    protected $allowedCountries       = ['US'];  // e.g. ['US','CA'] or empty for all
    protected $trustedISPsCacheFile;
    protected $trustedISPsCacheExpiry = 86400;
    protected $logFile;
    protected $htaccessFile;
    protected $whitelistFile;
    protected $blacklistFile;
    protected $rateLimitFile;
    protected $cacheFile;
    protected $whitelist              = [];
    protected $blacklist              = [];
    protected $ipCache                = [];
    protected $notificationCooldowns  = [];
    protected $rateWindow             = 60;
    protected $maxRequests            = 50;
    protected $notificationCooldown   = 3600;
    protected $botToken;
    protected $chatId;
    protected $apiKey;
    protected $debugMode              = false;
    protected $lastReason             = '';
    protected $lastIpData             = [];
    protected $consoleLogs            = [];

    public function __construct(array $config = []) {
        // File paths
        $this->logFile              = LOGS_DIR . 'bots.txt';
        $this->htaccessFile         = ROOT_DIR . '.htaccess';
        $this->whitelistFile        = ROOT_DIR . 'whitelist.dat';
        $this->blacklistFile        = ROOT_DIR . 'blacklist.dat';
        $this->rateLimitFile        = ROOT_DIR . 'rate_limit.json';
        $this->cacheFile            = ROOT_DIR . 'ipdetective_cache.json';
        $this->trustedISPsCacheFile = ROOT_DIR . 'trusted_isps_cache.json';

        // API credentials
        $this->botToken = TELEGRAM_BOT_TOKEN;
        $this->chatId   = TELEGRAM_CHAT_ID;
        $this->apiKey   = IPDETECTIVE_API_KEY;

        // Override defaults from config
        $this->debugMode             = $config['debug_mode'] ?? $this->debugMode;
        $this->rateWindow            = $config['rate_window'] ?? $this->rateWindow;
        $this->maxRequests           = $config['max_requests'] ?? $this->maxRequests;
        $this->notificationCooldown  = $config['notification_cooldown'] ?? $this->notificationCooldown;
        $this->trustedISPsCacheExpiry= $config['trusted_isps_cache_expiry'] ?? $this->trustedISPsCacheExpiry;
        $this->allowedCountries      = $config['allowed_countries'] ?? $this->allowedCountries;

        $this->initializeSystem();
        $this->loadTrustedISPs();
    }

    private function initializeSystem(): void {
        // Ensure directories exist
        foreach ([$this->logFile, $this->htaccessFile, $this->whitelistFile, $this->blacklistFile, $this->cacheFile] as $file) {
            $dir = dirname($file);
            if (!file_exists($dir)) {
                mkdir($dir, 0755, true);
            }
        }
        $this->loadWhitelist();
        $this->loadBlacklist();
        $this->loadIpCache();
    }

    private function loadWhitelist(): void {
        $this->whitelist = file_exists($this->whitelistFile) ? array_map('trim', file($this->whitelistFile)) : [];
    }

    private function loadBlacklist(): void {
        $this->blacklist = file_exists($this->blacklistFile) ? array_map('trim', file($this->blacklistFile)) : [];
    }

    private function loadIpCache(): void {
        $this->ipCache = file_exists($this->cacheFile) ? json_decode(file_get_contents($this->cacheFile), true) : [];
    }

    private function saveIpCache(): void {
        file_put_contents($this->cacheFile, json_encode($this->ipCache, JSON_PRETTY_PRINT));
    }

    public function getIp(): string {
        $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
        if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $parts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            $candidate = trim($parts[0]);
            if (filter_var($candidate, FILTER_VALIDATE_IP)) {
                $ip = $candidate;
            }
        }
        return $ip;
    }

    public function checkBot(): bool {
        $ip = $this->getIp();
        if (in_array($ip, $this->whitelist, true)) {
            return false;
        }
        if ($this->isIpBlockedInHtaccess($ip)) {
            return true;
        }
        if (in_array($ip, $this->blacklist, true)) {
            return $this->block($ip, 'Blacklisted IP');
        }
        if (!$this->checkRateLimit($ip)) {
            return $this->triggerCaptcha($ip, 'Rate Limit Exceeded');
        }

        $data = $this->getIPDetectiveData($ip);
        $this->lastIpData = $data;
        if (empty($data)) {
            return false;
        }

        if (in_array($data['asn_description'] ?? '', $this->trustedISPs, true)) {
            $this->addToWhitelist($ip);
            return false;
        }

        return $this->evaluateSuspicion($ip, $data);
    }

    protected function evaluateSuspicion(string $ip, array $data): bool {
        $score = 0;
        $breakdown = [];
        foreach (['bot'=>50,'proxy'=>25,'vpn'=>25] as $key => $pts) {
            if (!empty($data[$key])) {
                $score += $pts;
                $breakdown[] = "$key=$pts";
            }
        }
        if (($data['type'] ?? '') === 'datacenter') {
            $score += 20;
            $breakdown[] = 'datacenter=20';
        }
        if (!in_array($data['asn_description'] ?? '', $this->trustedISPs, true)) {
            $score += 15;
            $breakdown[] = 'untrusted_asn=15';
        }
        // Country check: enforce only if specified
        $country = strtoupper($data['country_code'] ?? '');
        if (!empty($this->allowedCountries) && !in_array($country, array_map('strtoupper', $this->allowedCountries), true)) {
            $score += 15;
            $breakdown[] = 'restricted_country=15';
        }

        $this->logConsole("Suspicious score for $ip: $score (" . implode(',', $breakdown) . ")");
        if ($score >= 60) {
            $reason = "Suspicious Behavior Detected (Score: $score)";
            $this->notify($ip, $reason, implode(', ', $breakdown));
            return $this->block($ip, $reason);
        }
        return false;
    }

    private function isIpBlockedInHtaccess(string $ip): bool {
        return file_exists($this->htaccessFile) && preg_match("/deny from $ip/i", file_get_contents($this->htaccessFile));
    }

    private function checkRateLimit(string $ip): bool {
        $now = time();
        $limits = file_exists($this->rateLimitFile) ? json_decode(file_get_contents($this->rateLimitFile), true) : [];
        if (!isset($limits[$ip]) || $now - $limits[$ip]['window'] > $this->rateWindow) {
            $limits[$ip] = ['count'=>1, 'window'=>$now];
        } else {
            $limits[$ip]['count']++;
        }
        file_put_contents($this->rateLimitFile, json_encode($limits));
        return $limits[$ip]['count'] <= $this->maxRequests;
    }

    private function getIPDetectiveData(string $ip): array {
        if (isset($this->ipCache[$ip]) && time() - $this->ipCache[$ip]['timestamp'] < 86400) {
            return $this->ipCache[$ip]['data'];
        }
        $url = "https://api.ipdetective.io/ip/$ip?info=true";
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER     => ["x-api-key: {$this->apiKey}"],
            CURLOPT_TIMEOUT        => 10
        ]);
        $res = curl_exec($ch);
        if ($res === false) {
            $err = curl_error($ch);
            $this->logConsole("CURL error for $ip: $err");
            $this->logToFile("CURL error for $ip: $err");
            curl_close($ch);
            return [];
        }
        curl_close($ch);
        $data = json_decode($res, true);
        if (!$data || !isset($data['ip'])) {
            $this->logConsole("Invalid response for $ip");
            $this->logToFile("Invalid IPDetective response for $ip: $res");
            return [];
        }
        $this->ipCache[$ip] = ['timestamp'=>time(), 'data'=>$data];
        $this->saveIpCache();
        return $data;
    }

    protected function notify(string $ip, string $reason, string $details = ''): void {
        if (!$this->botToken || !$this->chatId) return;
        // Daily Remaining Credits
        $credits   = $this->fetchRemainingCredits();
        $remaining = $credits['remaining'] ?? 'Unknown';
        $total     = $credits['total'] ?? 'Unknown';

        $msg = "💥 *#Blocked*\n" .
            "*IP:* `$ip`\n" .
            "*Reason:* `$reason`\n" .
            ($details ? "*Details:* `$details`\n" : '') .
            "*DRC:* `$remaining` (Total: `$total`)\n" .
            "*ASN:* `" . ($this->lastIpData['asn_description'] ?? 'Unknown') . "`\n" .
            "*Type:* `" . ($this->lastIpData['type'] ?? 'Unknown') . "`\n" .
            "*Country:* `" . ($this->lastIpData['country_code'] ?? 'Unknown') . "`\n" .
            "*Time:* `" . date('Y-m-d H:i:s') . "`";
        $this->sendTelegram($msg);
    }

    private function sendTelegram(string $msg): void {
        $url = "https://api.telegram.org/bot{$this->botToken}/sendMessage";
        $data = [
            'chat_id'    => $this->chatId,
            'text'       => $msg,
            'parse_mode' => 'Markdown'
        ];
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => http_build_query($data)
        ]);
        curl_exec($ch); curl_close($ch);
    }

    private function addToWhitelist(string $ip): void {
        if (!in_array($ip, $this->whitelist, true)) {
            file_put_contents($this->whitelistFile, "$ip\n", FILE_APPEND);
            $this->whitelist[] = $ip;
        }
    }

    private function block(string $ip, string $reason): bool {
        if (!filter_var($ip, FILTER_VALIDATE_IP) || $ip === '127.0.0.1') return false;
        file_put_contents($this->htaccessFile, "deny from $ip
", FILE_APPEND);
        header("Location: access_denied.php?" . http_build_query(['ip'=>$ip,'country'=>$this->lastIpData['country_code'] ?? 'Unknown']));
        exit;
    }

    private function triggerCaptcha(string $ip, string $reason): bool {
        header("Location: captcha_verification.php?" . http_build_query(['ip'=>$ip,'reason'=>$reason]));
        exit;
    }

    public function fetchRemainingCredits(): array {
        $url = "https://api.ipdetective.io/usage";
        $ch = curl_init($url);
        curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_HTTPHEADER=>["x-api-key: {$this->apiKey}"], CURLOPT_TIMEOUT=>5]);
        $res = curl_exec($ch); curl_close($ch);
        $data = json_decode($res, true);
        if (isset($data['lookup_limit'], $data['lookup_hits'])) {
            $total = (int)$data['lookup_limit'];
            $used  = (int)$data['lookup_hits'];
            return [
                'remaining'    => $total - $used,
                'used'         => $used,
                'total'        => $total,
                'percent_used' => round(($used/$total)*100,2)
            ];
        }
        return ['remaining'=>'Unknown','used'=>'Unknown','total'=>'Unknown','percent_used'=>0];
    }

    private function loadTrustedISPs(): void {
        if ($this->loadTrustedISPsFromCache()) return;
        $file = ROOT_DIR . 'trusted_isps.txt';
        if (!file_exists($file)) return;
        $list = array_filter(array_map('trim', file($file)));
        sort($list);
        $this->trustedISPs = $list;
        $this->cacheTrustedISPs();
    }

    private function loadTrustedISPsFromCache(): bool {
        if (!file_exists($this->trustedISPsCacheFile)) return false;
        $cache = json_decode(file_get_contents($this->trustedISPsCacheFile), true);
        if (!$cache || time() - $cache['timestamp'] > $this->trustedISPsCacheExpiry) return false;
        $this->trustedISPs = $cache['isps'];
        return true;
    }

    private function cacheTrustedISPs(): void {
        file_put_contents($this->trustedISPsCacheFile, json_encode(['timestamp'=>time(),'isps'=>$this->trustedISPs], JSON_PRETTY_PRINT));
    }

    // Accessors
    public function getTrustedISPs(): array { return $this->trustedISPs; }
    public function getAllowedCountries(): array { return $this->allowedCountries; }
    public function getLastReason(): string { return $this->lastReason; }
    public function getLastIpData(): array { return $this->lastIpData; }

    public function printConsoleLogs(): void {
        foreach ($this->consoleLogs as $log) {
            $safe = str_replace("'", "\\'", $log);
            echo "<script>console.log('[BotDetector_2] $safe');</script>";
        }
        $this->consoleLogs = [];
    }

    private function logToFile(string $message): void {
        $entry = date('Y-m-d H:i:s') . " - $message\n";
        file_put_contents($this->logFile, $entry, FILE_APPEND);
    }

    private function logConsole(string $message): void {
        $this->consoleLogs[] = $message;
    }
}
