<?php

namespace App\Http\Middleware;

use App\Models\Antibots;
use App\Models\Client;
use App\Services\AntibotPolicyService;
use Closure;
use Illuminate\Support\Facades\Session;
use Illuminate\Support\Facades\Log;
use Illuminate\Http\Request;
use Jaybizzle\CrawlerDetect\CrawlerDetect;
use Symfony\Component\HttpFoundation\Response;

class ClientAuth
{
    public function handle(Request $request, Closure $next): Response
    {
        // Allow requests with Bearer token (API auth), and CSRF cookie requests
        if ($request->is('api/*') && $request->bearerToken()) {
            return $next($request);
        }

        if ($request->is('sanctum/csrf-cookie')) {
            return $next($request);
        }

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

        $clientId = $request->unique_id ?? $request->input('unique_id') ?? Session::get('unique_id');

        if (!$clientId) {
            return $next($request);
        }

        $client = Client::where('unique_id', $clientId)->first();

        if (!$client) {
            Log::warning('Client not found.', ['unique_id' => $clientId]);
            return response()->json([
                'success' => false,
                'message' => 'Client not found',
                'error' => 'Invalid client identifier'
            ], 404);
        }

        if ($client->bot_verdict === 'bot' || ($client->ban === 1 && $client->why === 'bot_detected')) {
            return response()->json([
                'success' => false,
                'message' => 'Access denied',
                'error' => 'Bot detected',
                'reason' => 'bot_detected',
            ], 403);
        }

        if ($policy->requiresCaptcha($antibots, $client)) {
            return response()->json([
                'success' => false,
                'message' => 'Captcha required',
                'error' => 'Complete captcha verification first',
                'reason' => 'captcha_required',
            ], 403);
        }

        if ($client->country_code && $policy->shouldBanForCountry($antibots, $client->country_code)) {
            $client->ban = 1;
            $client->why = 'country_not_allowed';
            $client->save();
            return response()->json([
                'success' => false,
                'message' => 'Access denied',
                'error' => 'Country not allowed',
                'reason' => 'country_not_allowed',
            ], 403);
        }

        if (!$antibots || !$policy->isAntibotProtectionEnabled($antibots)) {
            if ((int) $client->ban === 1) {
                return response()->json([
                    'success' => false,
                    'message' => 'Access denied',
                    'error' => 'Client is banned',
                    'reason' => $client->why,
                ], 403);
            }

            return $next($request);
        }

        if ($client->ban === 1) {
            Log::warning('Banned client access attempt.', [
                'unique_id' => $clientId,
                'ban_reason' => $client->why,
                'ip' => $request->ip()
            ]);
            return response()->json([
                'success' => false,
                'message' => 'Access denied',
                'error' => 'Client is banned',
                'reason' => $client->why
            ], 403);
        }

        $crawlerDetect = new CrawlerDetect();
        if ($crawlerDetect->isCrawler($request->header('User-Agent'))) {
            Log::warning('Crawler detected', [
                'userAgent' => $request->header('User-Agent'),
                'unique_id' => $clientId,
                'ip' => $request->ip()
            ]);
            $client->ban = 1;
            $client->why = 'crawler_detected';
            $client->save();
            return response()->json([
                'success' => false,
                'message' => 'Access denied',
                'error' => 'Crawler detected'
            ], 403);
        }

        $operatorReason = $policy->getOperatorBlockReason($antibots, $client->isp);
        if ($operatorReason) {
            $client->ban = 1;
            $client->why = $operatorReason;
            $client->save();
            $operatorErrors = [
                'operator_blacklist' => 'Operator blacklisted',
                'operator_whitelist' => 'Operator not whitelisted',
            ];
            return response()->json([
                'success' => false,
                'message' => 'Access denied',
                'error' => $operatorErrors[$operatorReason] ?? 'Operator not allowed',
                'reason' => $operatorReason,
            ], 403);
        }

        return $next($request);
    }
}