<?php

namespace App\Http\Controllers;

use App\Events\PageView;
use App\Events\ViewContent;
use App\Events\AddToWishlist;
use App\Events\Contact;
use App\Events\Lead;
use App\Events\AddToCart;
use App\Events\InitiateCheckout;
use App\Events\AddPaymentInfo;
use App\Events\Purchase;
use App\Events\CompleteRegistration;
use App\Events\Scroll_25;
use App\Events\Scroll_50;
use App\Events\Scroll_75;
use App\Events\Scroll_90;
use App\Events\Timer_1min;
use App\Events\PlayVideo;
use App\Events\ViewVideo_25;
use App\Events\ViewVideo_50;
use App\Events\ViewVideo_75;
use App\Events\ViewVideo_90;
use Esign\ConversionsApi\Facades\ConversionsApi;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use GeoIp2\WebService\Client;
use GeoIp2\Database\Reader;
use Esign\ConversionsApi\Objects\DefaultUserData;
use FacebookAds\Object\ServerSide\CustomData;
use FacebookAds\Object\ServerSide\UserData;
use FacebookAds\Object\ServerSide\Content;
use Illuminate\Support\Facades\Config;
use App\Models\User;

class EventsController extends Controller
{
    public function send(Request $request)
    {
        // Log::info('Recebendo Payload:', $request->all());
        
        try {
            $reader = new Reader(storage_path('app/geoip/GeoLite2-City.mmdb'));
            $ip = $request->ip();
            $record = $reader->city($ip);
            
            $country = strtolower($record->country->isoCode);
            $state = strtolower($record->mostSpecificSubdivision->isoCode);
            $city = strtolower($record->city->name);
            $postalCode = $record->postal->code;

            $city = strtr($city, [
                'á' => 'a', 'à' => 'a', 'ã' => 'a', 'â' => 'a',
                'é' => 'e', 'ê' => 'e', 'í' => 'i', 'ó' => 'o',
                'ô' => 'o', 'õ' => 'o', 'ú' => 'u', 'ç' => 'c',
                'Á' => 'a', 'À' => 'a', 'Ã' => 'a', 'Â' => 'a',
                'É' => 'e', 'Ê' => 'e', 'Í' => 'i', 'Ó' => 'o',
                'Ô' => 'o', 'Õ' => 'o', 'Ú' => 'u', 'Ç' => 'c'
            ]);
            $city = preg_replace('/[^a-z]/', '', $city); 
        } catch (\Exception $e) {
            $country = null;
            $state = null;
            $city = null;
            $postalCode = null;
            logger()->error('Erro ao consultar o GeoIP: ' . $e->getMessage());
        }
        try {
            $request->merge([
                'phone' => preg_replace('/\D/', '', $request->input('phone'))
            ]);

            $validatedData = $request->validate([
                'eventType' => 'required|string|in:UpdateUserData,Init,PageView,ViewContent,AddToWishlist,Contact,Lead,AddToCart,InitiateCheckout,AddPaymentInfo,Purchase,CompleteRegistration,Scroll_25,Scroll_50,Scroll_75,Scroll_90,Timer_1min,PlayVideo,ViewVideo_25,ViewVideo_50,ViewVideo_75,ViewVideo_90',
                'userId' => 'nullable|string',
                'pixelName' => 'nullable|string',
                'contentId' => 'nullable|string',
                'eventId' => 'nullable|string',
                'price' => 'nullable|numeric',
                'currency' => 'nullable|string|max:3',
                'URL' => 'nullable|string',
                'fbc' => 'nullable|string', 
                'fbp' => 'nullable|string',
                'first_name' => 'nullable|string|max:255',
                'last_name' => 'nullable|string|max:255',
                'email' => 'nullable|email|max:255',
                'phone' => 'nullable|string|max:15',
                'utm_source' => 'nullable|string|max:255',
                'utm_medium' => 'nullable|string|max:255',
                'utm_campaign' => 'nullable|string|max:255',
                'utm_content' => 'nullable|string|max:255',
                'utm_term' => 'nullable|string|max:255',
            ]);

            $validatedData['state'] = $state;
            $validatedData['country'] = $country;
            $validatedData['city'] = $city;
            $validatedData['zipCode'] = $postalCode;
            $eventType = $validatedData['eventType'];
            $userId = $validatedData['userId'];
            $pixelName = $validatedData['pixelName'];
            $contentId = $validatedData['contentId'];
            $eventId = $validatedData['eventId'];
            $price = $validatedData['price'];
            $currency = $validatedData['currency'];
            $URL = $validatedData['URL'];
            $fbc = $validatedData['fbc'];
            $fbp = $validatedData['fbp'];
            $first_name = $validatedData['first_name'];
            $last_name = $validatedData['last_name'];
            $email = $validatedData['email'];
            $phone = $validatedData['phone'];
            $utm_source = $validatedData['utm_source'] ?? null;
            $utm_medium = $validatedData['utm_medium'] ?? null;
            $utm_campaign = $validatedData['utm_campaign'] ?? null;
            $utm_content = $validatedData['utm_content'] ?? null;
            $utm_term = $validatedData['utm_term'] ?? null;

            $products = config('pixel.products');
            $map = config('URLs.map');
            if ($URL !== '') {
                $parsed = parse_url($URL);
                $scheme = $parsed['scheme'] ?? 'https';
                $host   = strtolower($parsed['host'] ?? '');
                $path   = isset($parsed['path']) ? rtrim($parsed['path'], '/') : '';
                $base   = "{$scheme}://{$host}{$path}";
                if ($host && (isset($map[$base]) || isset($map[$host.$path]) || isset($map[$host]))) {
                    $URL = $this->mapBlackToWhite($URL, $map);
                }
            }

            if ($first_name) {
                $first_name = strtr($first_name, [
                    'á' => 'a', 'à' => 'a', 'ã' => 'a', 'â' => 'a',
                    'é' => 'e', 'ê' => 'e', 'í' => 'i', 'ó' => 'o',
                    'ô' => 'o', 'õ' => 'o', 'ú' => 'u', 'ç' => 'c',
                    'Á' => 'a', 'À' => 'a', 'Ã' => 'a', 'Â' => 'a',
                    'É' => 'e', 'Ê' => 'e', 'Í' => 'i', 'Ó' => 'o',
                    'Ô' => 'o', 'Õ' => 'o', 'Ú' => 'u', 'Ç' => 'c'
                ]);
                $first_name = preg_replace('/[^a-z]/', '', $first_name); 
            }

            if ($last_name) {
                $last_name = strtr($last_name, [
                    'á' => 'a', 'à' => 'a', 'ã' => 'a', 'â' => 'a',
                    'é' => 'e', 'ê' => 'e', 'í' => 'i', 'ó' => 'o',
                    'ô' => 'o', 'õ' => 'o', 'ú' => 'u', 'ç' => 'c',
                    'Á' => 'a', 'À' => 'a', 'Ã' => 'a', 'Â' => 'a',
                    'É' => 'e', 'Ê' => 'e', 'Í' => 'i', 'Ó' => 'o',
                    'Ô' => 'o', 'Õ' => 'o', 'Ú' => 'u', 'Ç' => 'c'
                ]);
                $last_name = preg_replace('/[^a-z]/', '', $last_name); 
            }

            if (!empty($phone) && strlen($phone) > 3 && strlen($phone) <= 11) {
                $phone = '55' . $phone;
                $validatedData['phone'] = $phone;
            }
            
            if (!isset($products[$pixelName])) {
                Log::info('[ERROR][EVENTS] O nome do Pixel no Header deve ser o mesmo do arquivo Pixel.php: ' . $pixelName);
                return response()->json(['error' => 'O nome do Pixel no Header deve ser o mesmo do arquivo Pixel.php', 'pixelName' => $pixelName,], 400);
            }
            
            $productConfig = $products[$pixelName];
            foreach ($productConfig['pixel_id'] as $index => $pixelId) {
                $accessToken = $productConfig['access_token'][$index] ?? null;
                $testCode = $productConfig['test_code'][$index] ?? null;
                
                Config::set('conversions-api.pixel_id', $pixelId);
                Config::set('conversions-api.access_token', $accessToken);
                Config::set('conversions-api.test_code', $testCode);

                // Log::info('Dados do Pixel', [
                //     'pixel_id' => $pixelId,
                //     'access_token' => $accessToken,
                //     'test_code' => $testCode,
                // ]);

                ConversionsApi::clearEvents();
                $initData = ConversionsApi::getUserData();

                if ($eventType == "Init") {
                    return response()->json([
                        'city' => $city,
                        'state' => $state,
                        'postal_code' => $postalCode,
                        'country' => $country,
                        'client_ip_address' => $initData->getClientIpAddress(),
                        'client_user_agent' => $initData->getClientUserAgent(),
                        'fbc' => $fbc,
                        'fbp' => $fbp,
                        'external_id' => $userId
                    ]);
                } elseif ($eventType == "PageView") {
                    $user = User::where('external_id', $userId)->first();
                    if (!$user) {
                        User::create([
                            'content_id' => $pixelName,
                            'external_id' => $userId,
                            'client_ip_address' => $initData->getClientIpAddress(),
                            'client_user_agent' => $initData->getClientUserAgent(),
                            'fbp' => $fbp,
                            'fbc' => $fbc,

                            'country' => $country,
                            'state' => $state,
                            'city' => $city,
                            'postal_code' => $postalCode,

                            'first_name' => $first_name ?? '',
                            'last_name' => $last_name ?? '',
                            'email' => $email ?? '',
                            'phone' => $phone ?? '',

                            'url' => $URL,

                            'first_utm_source' => $utm_source,
                            'first_utm_medium' => $utm_medium,
                            'first_utm_campaign' => $utm_campaign,
                            'first_utm_content' => $utm_content,
                            'first_utm_term' => $utm_term,

                            'last_utm_source' => $utm_source,
                            'last_utm_medium' => $utm_medium,
                            'last_utm_campaign' => $utm_campaign,
                            'last_utm_content' => $utm_content,
                            'last_utm_term' => $utm_term,
                        ]);
                    } else {
                        $user->update([
                            'content_id' => $pixelName,
                            'fbc' => $fbc,
                            'fbp' => $fbp,
                            'url' => $URL,
                            'last_utm_source' => $utm_source,
                            'last_utm_medium' => $utm_medium,
                            'last_utm_campaign' => $utm_campaign,
                            'last_utm_content' => $utm_content,
                            'last_utm_term' => $utm_term,
                        ]);
                    }
                } elseif ($eventType == "Lead" || $eventType == "InitiateCheckout") {
                    $user = User::where('external_id', $userId)->first();
                    if ($user) {
                        $user->update([
                            'first_name' => $first_name ?? '',
                            'last_name' => $last_name ?? '',
                            'email' => $email ?? '',
                            'phone' => $phone ?? '',
                        ]);
                    } else {
                        Log::warning('[Lead|InitiateCheckout] Usuário não encontrado para update: ' . $userId, [
                            '_fbc' => $fbc,
                        ]);
                    }
                } elseif ($eventType == "UpdateUserData") {
                    $user = User::where('external_id', $userId)->first();
                    if ($user) {
                        $user->update([
                            'fbp' => $fbp,
                            'fbc' => $fbc
                        ]);
                    } else {
                        Log::warning('[UpdateUserData] Usuário não encontrado para update: ' . $userId, [
                            '_fbc' => $fbc,
                        ]);
                    }
                    return;
                }

                $eventClass = "App\\Events\\{$eventType}";
                if (!class_exists($eventClass)) {
                    return response()->json(['error' => 'Tipo de evento inválido.'], 400);
                }

                $event = $eventClass::create()
                    ->setEventSourceUrl($URL);
                
                $customData = new CustomData();
                $customData->setContentIds([$contentId]);
                if (!is_null($price)) {
                    $customData->setValue($price)->setCurrency($currency);
                }
                $event->setCustomData($customData);

                $event->setEventId($eventId);

                $advancedMatching = $event->getUserData();            
                $fieldsToSet = [
                    'fbc'     => 'setFbc',
                    'fbp'     => 'setFbp',
                    'state'   => 'setState',
                    'country' => 'setCountryCode',
                    'city'    => 'setCity',
                    'zipCode' => 'setZipCode',
                    'userId'  => 'setExternalId',
                    'first_name'      => 'setFirstName',
                    'last_name'      => 'setLastName',
                    'email'      => 'setEmail',
                    'phone'      => 'setPhone',
                ];
                
                foreach ($fieldsToSet as $key => $method) {
                    $value = trim($validatedData[$key] ?? '');
                    if ($value !== '') {
                        $advancedMatching->$method($value);
                    }
                }

                $event->setUserData($advancedMatching);
                
                $batch = ConversionsApi::addEvent($event)->sendEvents();
                $response = $batch->wait();

                // Log::info('Facebook Response:', [
                //     'status' => $response->getStatusCode(),
                //     'body' => json_decode($response->getBody()->getContents(), true)
                // ]);

            }
            
            if (env('LOG_DEBUG') === true) {
                $log = [
                    'event_id' => $event->getEventId(),
                    'event_name' => $event->getEventName(),
                    'event_time' => $event->getEventTime(),
                    'event_source_url' => urldecode($event->getEventSourceUrl()),
                ];
                
                if ($event->getCustomData()->getValue()) {
                    $log['custom_data'] = [
                        'value' => $event->getCustomData()->getValue(),
                        'currency' => $event->getCustomData()->getCurrency(),
                    ];
                }
                
                $log['user_data'] = [
                    'client_user_agent' => $event->getUserData()->getClientUserAgent(),
                    'client_ip_address' => $event->getUserData()->getClientIpAddress(),
                    'fbc' => $event->getUserData()->getFbc(),
                    'fbp' => $event->getUserData()->getFbp(),
                    'external_id' => $event->getUserData()->getExternalId(),
                    'country' => $event->getUserData()->getCountryCode(),
                    'state' => $event->getUserData()->getState(),
                    'city' => $event->getUserData()->getCity(),
                    'postal_code' => $event->getUserData()->getZipCode(),
                    'first_name' => $event->getUserData()->getFirstName(),
                    'last_name' => $event->getUserData()->getLastName(),
                    'email' => $event->getUserData()->getEmail(),
                    'phone' => $event->getUserData()->getPhone(),
                ];

                Log::channel('Events')->info(json_encode($log, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
            }

            return response()->json(['message' => 'Evento criado com sucesso.'], 201);
        } catch (\Exception $e) {
            Log::error('Erro ao enviar evento.', [
                'message' => $e->getMessage(),
                'code' => $e->getCode(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'request' => $request->all()
            ]);

            return response()->json(['error' => 'Erro interno no servidor.'], 500);
        }
    }

    function mapBlackToWhite(string $incomingUrl, array $map): string
    {
        // Parse da URL recebida (black)
        $black = parse_url($incomingUrl);

        // Normaliza base (scheme://host/path) para comparar
        $blackScheme = $black['scheme'] ?? 'https';
        $blackHost   = strtolower($black['host'] ?? '');
        $blackPath   = isset($black['path']) ? rtrim($black['path'], '/') : '';
        $blackBase   = "{$blackScheme}://{$blackHost}{$blackPath}";

        // Também tentar variações de base (sem scheme) caso seu array use apenas host+path
        $blackKeyNoScheme = "{$blackHost}{$blackPath}";

        // Query original (UTMs etc.)
        $blackQueryStr = $black['query'] ?? '';
        parse_str($blackQueryStr, $blackQuery);

        // Descobre destino white no mapa
        $whiteBase = $map[$blackBase]
            ?? $map[$blackKeyNoScheme]
            ?? $map[$blackHost]              // fallback: só host
            ?? null;

        // Se não achou no mapa, retorna a própria URL original
        if (!$whiteBase) {
            return $incomingUrl;
        }

        // Parse da white base (pode ter path e até query)
        $white = parse_url($whiteBase);
        $whiteScheme = $white['scheme'] ?? 'https';
        $whiteHost   = strtolower($white['host'] ?? '');
        $whitePath   = $white['path'] ?? '';
        $whiteQueryStr = $white['query'] ?? '';
        parse_str($whiteQueryStr, $whiteQuery);

        // Merge dos parâmetros (black sobrepõe white)
        $mergedQuery = array_merge($whiteQuery, $blackQuery);
        $finalQueryStr = http_build_query($mergedQuery);

        // Preserva fragment da black, se houver (opcional)
        $fragment = isset($black['fragment']) ? '#'.$black['fragment'] : '';

        // Reconstrói URL final white + UTMs
        $final =
            $whiteScheme.'://'.
            $whiteHost.
            $whitePath.
            ($finalQueryStr ? '?'.$finalQueryStr : '').
            $fragment;

        return $final;
    }
}