<?php

namespace App\Jobs;

use App\Game\GlobalUserInfo;
use App\Game\WebChannelConfig;
use App\Services\ApkService;
use GuzzleHttp\Client;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class AfEvent implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $data;
    protected $user;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($data = [])
    {
        $this->data = $data;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        Log::channel('adjustEvent')->info('enter:'.json_encode($this->data));
        if (empty($this->data)) return;

        [$UserID, $payAmt, $AdId, $eventType, $channel, $pfType, $params] = $this->normalizePayload($this->data);

        if (!$UserID) {
            return;
        }

        if (empty($eventType)) $eventType = 2;

        Log::channel('adjustEvent')->info('接收数据' . \GuzzleHttp\json_encode($this->data));

        if ($this->isFacebookPlatform($pfType)) {
            $this->reportFacebookEvents($channel, $UserID, $payAmt, $AdId, $params);
            return;
        }
        if ($payAmt && !empty($AdId)) {
            // 执行AF事件
            $dao = new \App\dao\af\AfEvent();
            $dao->pay($AdId, $UserID, $eventType);
            $dao->paySum($AdId, $UserID, $payAmt, $eventType);
            $dao->payCount($AdId, $UserID, $eventType);
        }
//        $dao->recordKwaiRecharge($UserID, $payAmt);
//        $dao->recordGoogleRecharge($UserID, $payAmt);
    }

    protected function normalizePayload($data)
    {
        if (isset($data['UserID'])) {
            $user = GlobalUserInfo::getGameUserInfo('UserID', $data['UserID']);
            $this->user = $user;
            $params = is_array($data['params'] ?? null) ? $data['params'] : [];
            $orderSn = $params['order_sn'] ?? '';
            $orderInfo = $orderSn === '' ? null : DB::connection('write')->table('agent.dbo.order')
                ->where('order_sn', $orderSn)
                ->select('AdId', 'eventType','Channel')
                ->first();



            $channel = $data['channel']
                ?? ($orderInfo->Channel ?? null)
                ?? ($user->Channel ?? null)
                ?? $this->extractChannelFromCookie($data['UserID'])
                ?? 100;
            $channelConfig = $channel ? WebChannelConfig::getByChannel($channel) : null;

            $params['config'] = $channelConfig;
            $params['event_name'] = $data['event_name'] ?? ($params['event_name'] ?? '');
            $params['custom_data'] = is_array($data['custom_data'] ?? null) ? $data['custom_data'] : ($params['custom_data'] ?? []);

            Log::channel('adjustEvent')->info('normalizePayload:' . json_encode([
                    'user_id' => $data['UserID'] ?? 0,
                    'event_name' => $params['event_name'],
                    'order_sn' => $orderSn,
                    'order_channel' => $orderInfo->Channel ?? null,
                    'global_channel' => $user->Channel ?? null,
                    'final_channel' => $channel,
                    'platform_name' => $channelConfig->PlatformName ?? null,
                ], JSON_UNESCAPED_UNICODE));

            return [
                $data['UserID'] ?? 0,
                $params['golds'] ?? 0,
                $orderInfo->AdId ?? '',
                $orderInfo->eventType ?? 2,
                $channel,
                $channelConfig->PlatformName ?? '',
                $params,
            ];
        }

        return [
            $data[0] ?? 0,
            $data[1] ?? 0,
            $data[2] ?? '',
            $data[3] ?? 2,
            $data[4] ?? 0,
            $data[5] ?? '',
            $data[6] ?? [],
        ];
    }

    protected function isFacebookPlatform($pfType)
    {
        return is_string($pfType) && stripos($pfType, 'fb') !== false;
    }

    protected function reportFacebookEvents($channel, $userID, $payAmt, $adId, array $params = [])
    {
        try {
            $config = $params['config'] ?? null;
            if (!$config || !$this->isFacebookPlatform($config->PlatformName ?? '')) {
                Log::channel('adjustEvent')->info('facebook s2s skipped: invalid config', [
                    'channel' => $channel,
                    'user_id' => $userID,
                    'platform_name' => $config->PlatformName ?? null,
                ]);
                return;
            }

            $pixelId = trim((string)($config->PlatformID ?? ''));
            $accessToken = trim((string)($config->PlatformToken ?? ''));
            if ($pixelId === '' || $accessToken === '') {
                Log::channel('adjustEvent')->info('facebook s2s skipped: missing pixel config', [
                    'channel' => $channel,
                    'user_id' => $userID,
                    'pixel_id' => $pixelId,
                ]);
                return;
            }

            $events = $this->buildFacebookEvents($userID, $payAmt, $adId, $params);
            if (empty($events)) {
                return;
            }

            $url = "https://graph.facebook.com/v21.0/{$pixelId}/events";
            $payload = [
                'data' => $events,
                'access_token' => $accessToken,
            ];

            Log::channel('adjustEvent')->info('facebook s2s request ' . json_encode([
                    'channel' => $channel,
                    'user_id' => $userID,
                    'pixel_id' => $pixelId,
                    'event_count' => count($events),
                    'payload' => $payload,
                ], JSON_UNESCAPED_UNICODE));

            $client = new Client([
                'timeout' => 10,
                'http_errors' => false,
            ]);
            $response = $client->post($url, ['json' => $payload]);

            Log::channel('adjustEvent')->info('facebook s2s response ' . json_encode([
                    'channel' => $channel,
                    'user_id' => $userID,
                    'status' => $response->getStatusCode(),
                    'body' => (string)$response->getBody(),
                ], JSON_UNESCAPED_UNICODE));
        } catch (\Throwable $e) {
            Log::channel('adjustEvent')->info('facebook s2s failed ' . json_encode([
                    'channel' => $channel,
                    'user_id' => $userID,
                    'message' => $e->getMessage(),
                ], JSON_UNESCAPED_UNICODE));
        }
    }

    protected function buildFacebookEvents($userID, $payAmt, $adId, array $params = [])
    {
        $cookieInfo = $this->getFacebookCookieInfo($userID);

        if (!empty($params['event_name'])) {
            return $this->buildSingleFacebookEvent($userID, $adId, $params, $cookieInfo);
        }

        $orderSn = $params['order_sn'] ?? '';
        $first = !empty($params['first']);
        $isD0 = !empty($params['isd0']);
        $currency = env('CONFIG_24680_CURRENCY', 'BRL');

        $userData = $this->buildFacebookUserData($userID, $adId, $params, $cookieInfo);
        $customData = array_filter([
            'value' => (float)$payAmt,
            'currency' => $currency,
        ], function ($value) {
            return $value !== '' && $value !== null;
        });

        $origin = $cookieInfo['Origin'] ?? '';
        $events = [];

        if ($first) {
            if ($isD0) {
                $events[] = $this->makeFacebookEvent('firstpayD0', 'd0_' . $orderSn, $userData, $customData, $origin);
                $events[] = $this->makeFacebookEvent('AddToWishlist', 'aw_' . $orderSn, $userData, $customData, $origin);
            } else {
                $events[] = $this->makeFacebookEvent('firstpayD1', 'd1_' . $orderSn, $userData, $customData, $origin);
                $events[] = $this->makeFacebookEvent('AddToCart', 'ac_' . $orderSn, $userData, $customData, $origin);
            }
        } else if (!$isD0) {
            $events[] = $this->makeFacebookEvent('payagain', 'pa_' . $orderSn, $userData, $customData, $origin);
            $events[] = $this->makeFacebookEvent('InitiateCheckout', 'ic_' . $orderSn, $userData, $customData, $origin);
        }

        $events[] = $this->makeFacebookEvent('Purchase', 'pay_' . $orderSn, $userData, $customData, $origin);

        return $events;
    }

    protected function buildSingleFacebookEvent($userID, $adId, array $params = [], array $cookieInfo = [])
    {
        $user = $this->user;
        $eventName = trim((string)($params['event_name'] ?? ''));
        if ($eventName === '') {
            return [];
        }

        $eventId = $eventName . '_' . ($user->FPID ?? '');

        $customData = is_array($params['custom_data'] ?? null) ? $params['custom_data'] : [];
        $customData = array_filter($customData, function ($value) {
            return $value !== '' && $value !== null;
        });

        return [
            $this->makeFacebookEvent(
                $eventName,
                $eventId,
                $this->buildFacebookUserData($userID, $adId, $params, $cookieInfo),
                $customData,
                $cookieInfo['Origin'] ?? ''
            )
        ];
    }

    protected function buildFacebookUserData($userID, $adId, array $params = [], array $cookieInfo = [])
    {
        $user = $this->user;
        if (empty($cookieInfo)) {
            $cookieInfo = $this->getFacebookCookieInfo($userID);
        }
        $cookieValues = $this->parseCookieValues($cookieInfo['Cookie'] ?? '');
        $browserIds = $this->resolveFacebookBrowserIds($userID, $params, $cookieInfo, $cookieValues);

        $externalId = $params['udid'] ?? ($user ? md5($user->UserID) : md5($userID));

        $userData = [
            'external_id' => (string)$externalId,
            'fbp' => $browserIds['fbp'],
            'fbc' => $browserIds['fbc'],
            'client_ip_address' => $cookieInfo['IP'] ?? '',
            'client_user_agent' => $cookieInfo['ClickUA'] ?? $cookieInfo['GameUA'] ?? '',
        ];

        return array_filter($userData, function ($value) {
            return $value !== '' && $value !== null;
        });
    }

    protected function getFacebookCookieInfo($userID)
    {
        $user = $this->user;
        return ApkService::loadCookie($userID, $user->FPID ?? '', $user->FF ?? '') ?: [];
    }

    protected function parseCookieValues($cookieString)
    {
        $cookies = [];
        if (!is_string($cookieString) || $cookieString === '') {
            return $cookies;
        }

        foreach (explode(';', $cookieString) as $part) {
            $part = trim($part);
            if ($part === '' || strpos($part, '=') === false) {
                continue;
            }

            [$name, $value] = explode('=', $part, 2);
            $cookies[trim($name)] = trim($value);
        }

        return $cookies;
    }

    protected function resolveFacebookBrowserIds($userID, array $params, array $cookieInfo, array $cookieValues)
    {
        $fbp = trim((string)($cookieValues['_fbp'] ?? ''));
        $fbc = trim((string)($cookieValues['_fbc'] ?? ''));
        $cookieParamsFbclid = '';

        if (!empty($cookieInfo['Params'])) {
            $cookieParams = json_decode($cookieInfo['Params'], true);
            if (is_array($cookieParams)) {
                $cookieParamsFbclid = trim((string)($cookieParams['fbclid'] ?? ''));
            }
        }

        if ($cookieParamsFbclid === '') {
            return compact('fbp', 'fbc');
        }

        $timestamp = $this->resolveFacebookCookieTimestamp($cookieInfo);
        $currentFbclid = ApkService::extractFbclid($fbc);

        if ($fbc === '' || $currentFbclid === '' || $currentFbclid !== $cookieParamsFbclid) {
            $fbc = 'fb.1.' . $timestamp . '.' . $cookieParamsFbclid;
        }

        if ($fbp === '') {
            $seed = implode('|', [
                $userID,
                $cookieInfo['FPID'] ?? '',
                $cookieInfo['FF'] ?? '',
                $cookieInfo['IP'] ?? '',
                $cookieInfo['CreateTime'] ?? '',
            ]);
            $fbp = 'fb.1.' . $timestamp . '.' . substr(md5($seed), 0, 16);
        }

        return compact('fbp', 'fbc');
    }

    protected function resolveFacebookCookieTimestamp(array $cookieInfo)
    {
        $rawTime = $cookieInfo['CreateTime'] ?? '';
        if (!empty($rawTime)) {
            $timestamp = strtotime((string)$rawTime);
            if ($timestamp !== false) {
                return (string)($timestamp * 1000);
            }
        }

        return (string)round(microtime(true) * 1000);
    }

    protected function extractChannelFromCookie($userID)
    {
        $cookieInfo = $this->getFacebookCookieInfo($userID);
        if (!$cookieInfo || empty($cookieInfo['Params'])) {
            return null;
        }

        $params = json_decode($cookieInfo['Params'], true);
        if (!is_array($params)) {
            return null;
        }

        return $params['c'] ?? null;
    }

    protected function makeFacebookEvent($eventName, $eventId, array $userData, array $customData, $eventSourceUrl = '')
    {
        $event = [
            'event_name' => $eventName,
            'event_time' => time(),
            'event_id' => $eventId,
            'action_source' => 'website',
            'user_data' => $userData,
        ];

        if (!empty($customData)) {
            $event['custom_data'] = (object)$customData;
        }

        if (!empty($eventSourceUrl)) {
            $event['event_source_url'] = $eventSourceUrl;
        }

        return $event;
    }
}
