<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\{Log, Auth, Session};
use Tymon\JWTAuth\Facades\JWTAuth;
use App\Classes\Modules\Affiliate\Services\TracksAffiliateClick;

class TrackAffiliateClick
{
    public function handle(Request $request, Closure $next)
    {
        $isAuthenticated = $this->checkWebAuth() || $this->checkJwtAuth($request);

        if (!$isAuthenticated && $request->filled('tracking')) {
            $trackingCode = $this->validateTrackingCode($request->get('tracking'));
            if ($trackingCode) {
                $this->trackClick($trackingCode);
            }
        }

        return $next($request);
    }

    /**
     * Validate and sanitize tracking code
     * 
     * @param mixed $code
     * @return string|null
     */
    private function validateTrackingCode($code): ?string
    {
        if (!is_string($code)) {
            return null;
        }

        // Trim whitespace
        $code = trim($code);
        
        // Check length (max 255 chars based on database schema)
        if (strlen($code) > 255 || strlen($code) < 1) {
            return null;
        }

        // Only allow alphanumeric characters, hyphens, and underscores
        // This matches typical affiliate code formats
        if (!preg_match('/^[a-zA-Z0-9_-]+$/', $code)) {
            return null;
        }

        return $code;
    }

    /**
     * Check if user is authenticated via WEB session
     */
    private function checkWebAuth(): bool
    {
        try {
            if (Auth::guard('web')->check()) {
                return true;
            }

            // fallback session check
            foreach (Session::all() as $key => $value) {
                if (strpos($key, 'login_web_') === 0 && !empty($value)) {
                    return true;
                }
            }
        } catch (\Exception $e) {
            Log::warning('AffiliateClickMiddleware: Web auth error', ['error' => $e->getMessage()]);
        }

        return false;
    }

    /**
     * Check if user is authenticated via JWT token
     */
    private function checkJwtAuth(Request $request): bool
    {
        try {
            $token =
                $this->getBearerToken($request) ??
                $request->get('token') ??
                $request->cookie('access_token') ??
                $request->cookie('user-token');

            if (!$token) {
                return false;
            }

            JWTAuth::setToken($token);
            $user = JWTAuth::authenticate();

            if ($user) {
                return true;
            }
        } catch (\Exception $e) {
            Log::debug('AffiliateClickMiddleware: JWT invalid', ['error' => $e->getMessage()]);
        }

        return false;
    }

    /**
     * Extract Bearer token
     */
    private function getBearerToken(Request $request): ?string
    {
        if (!$request->hasHeader('Authorization')) return null;

        return preg_match('/Bearer\s+(.*)$/i', $request->header('Authorization'), $m)
            ? $m[1]
            : null;
    }

    /**
     * Track affiliate click once per session
     */
    private function trackClick(string $trackingCode): void
    {
        // Use a single session key with an array to prevent session bloat
        $trackedClicks = Session::get('affiliate_clicks_tracked', []);
        
        // Check if this code has already been tracked in this session
        if (in_array($trackingCode, $trackedClicks)) {
            return; // Already tracked
        }
        
        // Execute tracking
        app(TracksAffiliateClick::class)->execute($trackingCode);
        
        // Add to tracked list
        $trackedClicks[] = $trackingCode;
        
        // Limit array size to prevent DoS (keep only last 10 clicks)
        if (count($trackedClicks) > 10) {
            $trackedClicks = array_slice($trackedClicks, -10);
        }
        
        Session::put('affiliate_clicks_tracked', $trackedClicks);
    }
}
