<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\AccountsInfo;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class AccountCookieController extends Controller
{
    public function index(Request $request)
    {
        $filters = $this->buildFilters($request);

        $cookieSubQuery = DB::connection('read')->raw("
            (
                SELECT *,
                       ROW_NUMBER() OVER (
                           PARTITION BY
                               ISNULL(CAST(UserID AS VARCHAR(50)), '')
                           ORDER BY CreateTime DESC, ID DESC
                       ) AS rn
                FROM QPAccountsDB.dbo.AccountCookie
            ) ac
        ");

        $query = DB::connection('read')
            ->table($cookieSubQuery)
            ->leftJoin(AccountsInfo::TABLE . ' as ai', 'ai.UserID', '=', 'ac.UserID')
            ->select([
                'ac.ID',
                'ac.UserID',
                'ai.GameID',
                'ai.Channel as AccountChannel',
                'ai.RegisterDate',
                'ac.UrlSign',
                'ac.Platform',
                'ac.CreateTime',
                'ac.IP',
                'ac.Locale',
                'ac.Origin',
                'ac.FPID',
                'ac.FF',
                'ac.ClickUA',
                'ac.GameUA',
                'ac.Params',
                'ac.Cookie',
            ]);

        $this->applyFilters($query, $filters);
        $query->where('ac.rn', 1);

        $stats = $this->buildStats(clone $query);
        $fbclidGroups = $this->buildFbclidGroups(clone $query);
        $ffGroups = $this->buildDuplicateValueGroups(clone $query, 'FF', 'ff');

        $list = $query
            ->orderBy('ac.CreateTime', 'desc')
            ->paginate($filters['page_size'])
            ->appends($request->query());

        $userIds = $list->getCollection()
            ->pluck('UserID')
            ->filter(function ($userId) {
                return !empty($userId);
            })
            ->map(function ($userId) {
                return (int)$userId;
            })
            ->unique()
            ->values()
            ->all();

        $payMap = $this->loadPayStats($userIds);
        $adjustMap = $this->loadAdjustEventStats($userIds, $filters);

        $items = $list->getCollection()->map(function ($row) {
            $params = $this->decodeJson($row->Params);
            $cookieMap = $this->parseCookieString($row->Cookie);
            $uaInfo = $this->analyzeUserAgent($row->ClickUA ?: $row->GameUA);
            $paramAnalysis = $this->analyzeMarketingParams($params);

            $row->HasFbclid = stripos($row->Params ?? '', 'fbclid') !== false;
            $row->Fbp = $cookieMap['_fbp'] ?? '';
            $row->Fbc = $cookieMap['_fbc'] ?? ($params['fbclid'] ?? '');
            $row->Pixel = $paramAnalysis['primary']['pixel'];
            $row->UtmSource = $paramAnalysis['primary']['utm_source'];
            $row->UtmMedium = $paramAnalysis['primary']['utm_medium'];
            $row->UtmCampaign = $paramAnalysis['primary']['utm_campaign'];
            $row->ParamChannel = $paramAnalysis['primary']['channel'];
            $row->ParamCampaign = $paramAnalysis['primary']['campaign'];
            $row->ParamAdgroup = $paramAnalysis['primary']['adgroup'];
            $row->ParamCreative = $paramAnalysis['primary']['creative'];
            $row->UaApp = $uaInfo['app'];
            $row->UaOs = $uaInfo['os'];
            $row->UaDevice = $uaInfo['device'];
            $row->CookieKey = $this->makeCookieKey($row);
            $row->ParamsDecoded = $params;
            $row->ParamAnalysis = $paramAnalysis;
            $row->FbclidValue = $paramAnalysis['primary']['fbclid'];
            $row->FbclidGroup = null;
            $row->FFGroup = null;
            $row->FbclidCookieCheck = $this->validateFbclidCookieConsistency(
                $paramAnalysis['primary']['fbclid'],
                $cookieMap['_fbc'] ?? ''
            );

            return $row;
        });

        $items = $items->map(function ($row) use ($payMap, $adjustMap, $fbclidGroups, $ffGroups) {
            $pay = $payMap[(int)($row->UserID ?? 0)] ?? null;
            $adjust = $adjustMap[(int)($row->UserID ?? 0)] ?? null;
            $fbclidGroup = $fbclidGroups['rows'][$row->ID] ?? null;
            $ffGroup = $ffGroups['rows'][$row->ID] ?? null;

            $row->PayOrderCount = $pay->pay_order_count ?? 0;
            $row->PayAmountSum = $pay->pay_amount_sum ?? 0;
            $row->PayAmountDisplay = (string)round(((float)($row->PayAmountSum ?? 0)) / 100);
            $row->LastPayAt = $pay->last_pay_at ?? '';
            $row->AdjustStatus = $adjust['status'] ?? 'none';
            $row->AdjustLogs = $adjust['logs'] ?? [];
            $row->FbclidGroup = $fbclidGroup;
            $row->FFGroup = $ffGroup;

            return $row;
        });

        $list->setCollection($items);

        return view('admin.account_cookie.index', [
            'list' => $list,
            'filters' => $filters,
            'stats' => $stats,
            'fbclidGroups' => $fbclidGroups['groups'],
            'ffGroups' => $ffGroups['groups'],
        ]);
    }

    protected function buildFilters(Request $request)
    {
        $gameId = trim((string)$request->input('GameID', ''));
        $resolvedUserId = '';
        if ($gameId !== '') {
            $resolvedUserId = AccountsInfo::query()->where('GameID', $gameId)->value('UserID') ?: '';
        }

        $dateStartRaw = trim((string)$request->input('date_start', date('Y-m-d')));
        $dateEndRaw = trim((string)$request->input('date_end', date('Y-m-d')));
        $registerStartRaw = trim((string)$request->input('register_start', date('Y-m-d')));
        $registerEndRaw = trim((string)$request->input('register_end', date('Y-m-d')));

        return [
            'user_id' => trim((string)$request->input('UserID', '')),
            'game_id' => $gameId,
            'resolved_user_id' => $resolvedUserId,
            'url_signs' => $this->splitCsv($request->input('UrlSign', '')),
            'account_channels' => $this->splitCsv($request->input('AccountChannel', '')),
            'platform' => trim((string)$request->input('Platform', '')),
            'date_start_raw' => $dateStartRaw,
            'date_end_raw' => $dateEndRaw,
            'register_start_raw' => $registerStartRaw,
            'register_end_raw' => $registerEndRaw,
            'date_start' => $this->normalizeDateBoundary($dateStartRaw, false),
            'date_end' => $this->normalizeDateBoundary($dateEndRaw, true),
            'register_start' => $this->normalizeDateBoundary($registerStartRaw, false),
            'register_end' => $this->normalizeDateBoundary($registerEndRaw, true),
            'has_fbclid' => (int)$request->input('has_fbclid', 1),
            'origin' => trim((string)$request->input('Origin', '')),
            'ip' => trim((string)$request->input('IP', '')),
            'ua' => trim((string)$request->input('UA', '')),
            'param_category' => trim((string)$request->input('param_category', '')),
            'param_key' => trim((string)$request->input('param_key', '')),
            'param_value' => trim((string)$request->input('param_value', '')),
            'page_size' => max(20, min((int)$request->input('page_size', 100), 500)),
        ];
    }

    protected function applyFilters($query, array $filters)
    {
        if ($filters['user_id'] !== '') {
            $query->where('ac.UserID', $filters['user_id']);
        }

        if ($filters['game_id'] !== '') {
            if ($filters['resolved_user_id'] !== '') {
                $query->where('ac.UserID', $filters['resolved_user_id']);
            } else {
                $query->whereRaw('1 = 0');
            }
        }

        if (!empty($filters['url_signs'])) {
            $query->whereIn('ac.UrlSign', $filters['url_signs']);
        }

        if (!empty($filters['account_channels'])) {
            $query->whereIn('ai.Channel', $filters['account_channels']);
        }

        if ($filters['platform'] !== '') {
            $query->where('ac.Platform', $filters['platform']);
        }

        if ($filters['date_start'] !== '') {
            $query->where('ac.CreateTime', '>=', $filters['date_start']);
        }
        if ($filters['date_end'] !== '') {
            $query->where('ac.CreateTime', '<=', $filters['date_end']);
        }

        if ($filters['register_start'] !== '') {
            $query->where('ai.RegisterDate', '>=', $filters['register_start']);
        }
        if ($filters['register_end'] !== '') {
            $query->where('ai.RegisterDate', '<=', $filters['register_end']);
        }

        if ($filters['has_fbclid'] === 1) {
            $query->where('ac.Params', 'like', '%fbclid%');
        } elseif ($filters['has_fbclid'] === 2) {
            $query->where('ac.Params', 'not like', '%fbclid%');
        }

        if ($filters['origin'] !== '') {
            $query->where('ac.Origin', 'like', '%' . $filters['origin'] . '%');
        }

        if ($filters['ip'] !== '') {
            $query->where('ac.IP', 'like', '%' . $filters['ip'] . '%');
        }

        if ($filters['ua'] !== '') {
            $query->where(function ($subQuery) use ($filters) {
                $subQuery->where('ac.ClickUA', 'like', '%' . $filters['ua'] . '%')
                    ->orWhere('ac.GameUA', 'like', '%' . $filters['ua'] . '%');
            });
        }

        if ($filters['param_key'] !== '') {
            $query->where('ac.Params', 'like', '%"' . $filters['param_key'] . '"%');
        }

        if ($filters['param_value'] !== '') {
            $query->where('ac.Params', 'like', '%' . $filters['param_value'] . '%');
        }

        if ($filters['param_category'] !== '') {
            $keys = $this->getCategoryKeys($filters['param_category']);
            if (empty($keys)) {
                $query->whereRaw('1 = 0');
            } else {
                $query->where(function ($subQuery) use ($keys) {
                    foreach ($keys as $key) {
                        $subQuery->orWhere('ac.Params', 'like', '%"' . $key . '"%');
                    }
                });
            }
        }
    }

    protected function buildStats($query)
    {
        $rows = $query->get([
            'ac.ID',
            'ac.UserID',
            'ac.FPID',
            'ac.FF',
            'ac.UrlSign',
            'ac.Platform',
            'ac.IP',
            'ac.Origin',
            'ac.ClickUA',
            'ac.GameUA',
            'ac.Params',
        ]);

        $stats = [
            'total' => $rows->count(),
            'unique_users' => $rows->pluck('UserID')->filter()->unique()->count(),
            'unique_ips' => $rows->pluck('IP')->filter()->unique()->count(),
            'unique_cookies' => $rows->map(function ($row) {
                return $this->makeCookieKey($row);
            })->filter()->unique()->count(),
            'registered_users' => $rows->filter(function ($row) {
                return !empty($row->UserID);
            })->pluck('UserID')->unique()->count(),
            'paid_users' => 0,
            'fbclid_count' => 0,
            'fb_inapp_count' => 0,
            'ig_inapp_count' => 0,
            'platforms' => [],
            'url_signs' => [],
            'origins' => [],
            'utm_sources' => [],
            'param_categories' => [],
            'param_keys' => [],
            'param_category_stats' => [],
            'duplicate_fbclid_groups' => 0,
            'duplicate_fbclid_rows' => 0,
            'duplicate_ff_groups' => 0,
            'duplicate_ff_rows' => 0,
            'fbclid_cookie_issues' => 0,
        ];

        $fbclidBuckets = [];
        $ffBuckets = [];

        foreach ($rows as $row) {
            $params = $this->decodeJson($row->Params);
            $uaInfo = $this->analyzeUserAgent($row->ClickUA ?: $row->GameUA);
            $paramAnalysis = $this->analyzeMarketingParams($params);
            $cookieMap = $this->parseCookieString($row->Cookie ?? '');

            if (stripos($row->Params ?? '', 'fbclid') !== false) {
                $stats['fbclid_count']++;
            }
            if ($uaInfo['app'] === 'Facebook') {
                $stats['fb_inapp_count']++;
            }
            if ($uaInfo['app'] === 'Instagram') {
                $stats['ig_inapp_count']++;
            }

            $this->incrementBucket($stats['platforms'], $row->Platform ?: 'unknown');
            $this->incrementBucket($stats['url_signs'], (string)($row->UrlSign ?: 'unknown'));
            $this->incrementBucket($stats['origins'], $row->Origin ?: 'unknown');
            $this->incrementBucket($stats['utm_sources'], $params['utm_source'] ?? 'unknown');

            foreach ($paramAnalysis['categories'] as $category => $entries) {
                $label = $this->getParamCategoryLabel($category);
                $this->incrementBucket($stats['param_categories'], $label);

                if (!isset($stats['param_category_stats'][$category])) {
                    $stats['param_category_stats'][$category] = [
                        'label' => $label,
                        'keys' => [],
                        'values' => [],
                    ];
                }

                foreach ($entries as $entry) {
                    $this->incrementBucket($stats['param_category_stats'][$category]['keys'], $entry['key']);
                    $this->incrementBucket($stats['param_keys'], $entry['key']);

                    $valueLabel = $entry['key'] . '=' . $this->truncateParamValue($entry['value']);
                    $this->incrementBucket($stats['param_category_stats'][$category]['values'], $valueLabel);
                }
            }

            $fbclid = $paramAnalysis['primary']['fbclid'];
            if ($fbclid !== '') {
                $fbclidBuckets[$fbclid] = ($fbclidBuckets[$fbclid] ?? 0) + 1;
            }

            $ff = trim((string)($row->FF ?? ''));
            if ($ff !== '') {
                $ffBuckets[$ff] = ($ffBuckets[$ff] ?? 0) + 1;
            }

            $fbclidCookieCheck = $this->validateFbclidCookieConsistency(
                $paramAnalysis['primary']['fbclid'],
                $cookieMap['_fbc'] ?? ''
            );
            if (!$fbclidCookieCheck['ok']) {
                $stats['fbclid_cookie_issues']++;
            }
        }

        $stats['paid_users'] = $this->loadPaidUserCount(
            $rows->pluck('UserID')->filter()->map(function ($userId) {
                return (int)$userId;
            })->unique()->values()->all()
        );

        arsort($stats['platforms']);
        arsort($stats['url_signs']);
        arsort($stats['origins']);
        arsort($stats['utm_sources']);
        arsort($stats['param_categories']);
        arsort($stats['param_keys']);

        foreach ($stats['param_category_stats'] as &$categoryStats) {
            arsort($categoryStats['keys']);
            arsort($categoryStats['values']);
        }
        unset($categoryStats);

        foreach ($fbclidBuckets as $count) {
            if ($count > 1) {
                $stats['duplicate_fbclid_groups']++;
                $stats['duplicate_fbclid_rows'] += $count;
            }
        }

        foreach ($ffBuckets as $count) {
            if ($count > 1) {
                $stats['duplicate_ff_groups']++;
                $stats['duplicate_ff_rows'] += $count;
            }
        }

        return $stats;
    }

    protected function buildFbclidGroups($query)
    {
        $rows = $query->get([
            'ac.ID',
            'ac.Params',
        ]);

        $groupsByFbclid = [];

        foreach ($rows as $row) {
            $params = $this->decodeJson($row->Params);
            $fbclid = $this->analyzeMarketingParams($params)['primary']['fbclid'];
            if ($fbclid === '') {
                continue;
            }

            $groupsByFbclid[$fbclid][] = (int)$row->ID;
        }

        return $this->finalizeDuplicateGroups($groupsByFbclid, 'fbclid');
    }

    protected function buildDuplicateValueGroups($query, $field, $type)
    {
        $rows = $query->get([
            'ac.ID',
            'ac.' . $field,
        ]);

        $groups = [];

        foreach ($rows as $row) {
            $value = trim((string)($row->{$field} ?? ''));
            if ($value === '') {
                continue;
            }

            $groups[$value][] = (int)$row->ID;
        }

        return $this->finalizeDuplicateGroups($groups, $type);
    }

    protected function finalizeDuplicateGroups(array $groupedIds, $type)
    {
        $palettes = [
            'fbclid' => ['#fff3cd', '#d1ecf1', '#d4edda', '#f8d7da', '#e2d9f3', '#fde2b8', '#d6eaf8', '#f5c6cb'],
            'ff' => ['#e8f5e9', '#e3f2fd', '#fff8e1', '#fce4ec', '#ede7f6', '#e0f7fa', '#f1f8e9', '#fff3e0'],
        ];

        $palette = $palettes[$type] ?? ['#f5f5f5'];

        $groups = [];
        $rowMap = [];
        $groupIndex = 1;

        foreach ($groupedIds as $value => $ids) {
            $ids = array_values(array_unique($ids));
            if (count($ids) < 2) {
                continue;
            }

            $color = $palette[($groupIndex - 1) % count($palette)];
            $group = [
                'index' => $groupIndex,
                'value' => $value,
                'count' => count($ids),
                'color' => $color,
                'row_ids' => $ids,
                'type' => $type,
            ];

            $groups[] = $group;

            foreach ($ids as $id) {
                $rowMap[$id] = $group;
            }

            $groupIndex++;
        }

        return [
            'groups' => $groups,
            'rows' => $rowMap,
        ];
    }

    protected function validateFbclidCookieConsistency($paramFbclid, $cookieFbc)
    {
        $paramFbclid = trim((string)$paramFbclid);
        $cookieFbc = trim((string)$cookieFbc);
        $cookieFbclid = $this->extractFbclidFromFbc($cookieFbc);

        if ($paramFbclid === '' && $cookieFbclid === '') {
            return [
                'ok' => true,
                'status' => 'none',
                'cookie_fbclid' => '',
                'message' => '',
            ];
        }

        if ($paramFbclid !== '' && $cookieFbclid === '') {
            return [
                'ok' => false,
                'status' => 'missing_cookie_fbc',
                'cookie_fbclid' => '',
                'message' => 'Params 有 fbclid，但 Cookie 未解析出 _fbc/fbclid',
            ];
        }

        if ($paramFbclid === '' && $cookieFbclid !== '') {
            return [
                'ok' => false,
                'status' => 'missing_param_fbclid',
                'cookie_fbclid' => $cookieFbclid,
                'message' => 'Cookie 有 _fbc/fbclid，但 Params 缺少 fbclid',
            ];
        }

        if ($paramFbclid === $cookieFbclid) {
            return [
                'ok' => true,
                'status' => 'match',
                'cookie_fbclid' => $cookieFbclid,
                'message' => '匹配',
            ];
        }

        return [
            'ok' => false,
            'status' => 'mismatch',
            'cookie_fbclid' => $cookieFbclid,
            'message' => 'Params.fbclid 与 Cookie._fbc 中的 fbclid 不一致',
        ];
    }

    protected function extractFbclidFromFbc($cookieFbc)
    {
        $cookieFbc = trim((string)$cookieFbc);
        if ($cookieFbc === '') {
            return '';
        }

        $parts = explode('.', $cookieFbc, 4);
        if (count($parts) === 4 && $parts[0] === 'fb' && in_array($parts[1], ['1', '2'], true)) {
            return trim((string)$parts[3]);
        }

        return $cookieFbc;
    }

    protected function incrementBucket(array &$bucket, $key)
    {
        $bucket[$key] = ($bucket[$key] ?? 0) + 1;
    }

    protected function splitCsv($value)
    {
        return array_values(array_filter(array_map('trim', explode(',', (string)$value)), function ($item) {
            return $item !== '';
        }));
    }

    protected function normalizeDateBoundary($value, $endOfDay = false)
    {
        $value = trim((string)$value);
        if ($value === '') {
            return '';
        }

        $value = substr(str_replace('T', ' ', $value), 0, 10);
        return $value . ($endOfDay ? ' 23:59:59' : ' 00:00:00');
    }

    protected function decodeJson($json)
    {
        $data = json_decode((string)$json, true);
        return is_array($data) ? $data : [];
    }

    protected function analyzeMarketingParams(array $params)
    {
        $analysis = [
            'flat' => [],
            'categories' => [],
            'primary' => [
                'channel' => '',
                'utm_source' => '',
                'utm_medium' => '',
                'utm_campaign' => '',
                'campaign' => '',
                'adgroup' => '',
                'creative' => '',
                'pixel' => '',
                'fbclid' => '',
            ],
        ];

        foreach ($params as $key => $value) {
            if (is_array($value) || is_object($value)) {
                $value = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            }

            $key = trim((string)$key);
            $value = trim((string)$value);
            if ($key === '' || $value === '') {
                continue;
            }

            $category = $this->detectParamCategory($key);

            $analysis['flat'][$key] = $value;
            $analysis['categories'][$category][] = [
                'key' => $key,
                'value' => $value,
            ];
        }

        $analysis['primary']['channel'] = $analysis['flat']['c'] ?? ($analysis['flat']['channel'] ?? '');
        $analysis['primary']['utm_source'] = $analysis['flat']['utm_source'] ?? '';
        $analysis['primary']['utm_medium'] = $analysis['flat']['utm_medium'] ?? '';
        $analysis['primary']['utm_campaign'] = $analysis['flat']['utm_campaign'] ?? '';
        $analysis['primary']['campaign'] = $analysis['flat']['campaign'] ?? ($analysis['flat']['utm_campaign'] ?? '');
        $analysis['primary']['adgroup'] = $analysis['flat']['adgroup'] ?? ($analysis['flat']['adset'] ?? ($analysis['flat']['utm_term'] ?? ''));
        $analysis['primary']['creative'] = $analysis['flat']['creative'] ?? ($analysis['flat']['utm_content'] ?? '');
        $analysis['primary']['pixel'] = $analysis['flat']['pixel'] ?? ($analysis['flat']['pixelID'] ?? ($analysis['flat']['pixel_id'] ?? ''));
        $analysis['primary']['fbclid'] = $analysis['flat']['fbclid'] ?? '';

        return $analysis;
    }

    protected function detectParamCategory($key)
    {
        $normalizedKey = strtolower(trim((string)$key));

        if (strpos($normalizedKey, 'utm_') === 0) {
            return 'utm';
        }

        if (in_array($normalizedKey, ['campaign', 'adgroup', 'adset', 'ad_id', 'creative', 'creative_id', 'placement', 'site_source_name'], true)) {
            return 'campaign';
        }

        if (in_array($normalizedKey, ['fbclid', 'gclid', 'ttclid', 'msclkid', 'wbraid', 'gbraid', 'fbc', 'fbp', '_fbc', '_fbp', 'pixel', 'pixelid', 'pixel_id'], true)) {
            return 'attribution';
        }

        if (in_array($normalizedKey, ['c', 'channel', 'source', 'media_source', 'utm_source_platform', 'pid', 'af_channel', 'sub_channel'], true)) {
            return 'channel';
        }

        if (preg_match('/(_id|id)$/', $normalizedKey)) {
            return 'identifier';
        }

        return 'custom';
    }

    protected function getParamCategoryLabel($category)
    {
        $labels = [
            'utm' => 'UTM',
            'campaign' => 'Campaign',
            'attribution' => 'Attribution',
            'channel' => 'Channel',
            'identifier' => 'Identifier',
            'custom' => 'Custom',
        ];

        return $labels[$category] ?? ucfirst($category);
    }

    protected function getCategoryKeys($category)
    {
        $map = [
            'utm' => ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'utm_id', 'utm_source_platform'],
            'campaign' => ['campaign', 'adgroup', 'adset', 'ad_id', 'creative', 'creative_id', 'placement', 'site_source_name'],
            'attribution' => ['fbclid', 'gclid', 'ttclid', 'msclkid', 'wbraid', 'gbraid', 'fbc', 'fbp', '_fbc', '_fbp', 'pixel', 'pixelID', 'pixel_id'],
            'channel' => ['c', 'channel', 'source', 'media_source', 'pid', 'af_channel', 'sub_channel'],
            'identifier' => ['utm_id', 'campaign_id', 'adgroup_id', 'adset_id', 'creative_id', 'pixel_id', 'pixelID'],
        ];

        return $map[$category] ?? [];
    }

    protected function truncateParamValue($value, $length = 36)
    {
        $value = (string)$value;
        if ($value === '') {
            return '-';
        }

        return mb_strlen($value) > $length ? mb_substr($value, 0, $length) . '...' : $value;
    }

    protected function makeCookieKey($row)
    {
        if (!empty($row->FPID)) {
            return 'fpid:' . $row->FPID;
        }
        if (!empty($row->FF)) {
            return 'ff:' . $row->FF;
        }
        if (!empty($row->UserID)) {
            return 'uid:' . $row->UserID;
        }
        return 'row:' . ($row->ID ?? '');
    }

    protected function parseCookieString($cookieString)
    {
        $cookies = [];
        foreach (explode(';', (string)$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 analyzeUserAgent($ua)
    {
        $ua = (string)$ua;
        $app = 'Browser';
        if (stripos($ua, 'Instagram') !== false) {
            $app = 'Instagram';
        } elseif (stripos($ua, 'FBAN') !== false || stripos($ua, 'FBAV') !== false || stripos($ua, 'Facebook') !== false) {
            $app = 'Facebook';
        }

        $os = 'Unknown';
        if (stripos($ua, 'iPhone') !== false || stripos($ua, 'iPad') !== false || stripos($ua, 'iOS') !== false) {
            $os = 'iOS';
        } elseif (stripos($ua, 'Android') !== false) {
            $os = 'Android';
        }

        $device = 'Unknown';
        if (stripos($ua, 'iPhone') !== false) {
            $device = 'iPhone';
        } elseif (stripos($ua, 'iPad') !== false) {
            $device = 'iPad';
        } elseif (stripos($ua, 'Android') !== false) {
            $device = 'Android';
        }

        return compact('app', 'os', 'device');
    }

    protected function loadPaidUserCount(array $userIds)
    {
        if (empty($userIds)) {
            return 0;
        }

        return DB::connection('read')
            ->table('agent.dbo.order')
            ->whereIn('user_id', $userIds)
            ->where('pay_status', 1)
            ->distinct('user_id')
            ->count('user_id');
    }

    protected function loadPayStats(array $userIds)
    {
        if (empty($userIds)) {
            return [];
        }

        return DB::connection('read')
            ->table('agent.dbo.order')
            ->whereIn('user_id', $userIds)
            ->where('pay_status', 1)
            ->groupBy('user_id')
            ->selectRaw('user_id, count(*) as pay_order_count, cast(sum(amount) as decimal(18,2)) as pay_amount_sum, max(pay_at) as last_pay_at')
            ->get()
            ->keyBy('user_id')
            ->all();
    }

    protected function loadAdjustEventStats(array $userIds, array $filters)
    {
        if (empty($userIds)) {
            return [];
        }

        $result = [];
        $userIdMap = array_fill_keys(array_map('strval', $userIds), true);

        foreach ($this->resolveAdjustLogFiles($filters) as $logFile) {
            $handle = @fopen($logFile, 'r');
            if ($handle === false) {
                continue;
            }

            $currentUserId = null;

            while (($line = fgets($handle)) !== false) {
                $userId = $this->extractAdjustUserId($line);
                $status = $this->classifyAdjustLine($line);

                if ($userId !== null && isset($userIdMap[(string)$userId])) {
                    $currentUserId = $userId;
                } elseif ($userId === null && $currentUserId !== null && in_array($status, ['request', 'success', 'skipped', 'failed'], true)) {
                    $userId = $currentUserId;
                } else {
                    if ($status === 'enter') {
                        $currentUserId = null;
                    }
                    continue;
                }

                if (!isset($result[$userId])) {
                    $result[$userId] = ['status' => 'enter', 'logs' => []];
                }

                if ($status !== null) {
                    $result[$userId]['status'] = $status;
                }

                if (count($result[$userId]['logs']) < 50) {
                    $result[$userId]['logs'][] = trim($line);
                }
            }

            fclose($handle);
        }

        return $result;
    }

    protected function resolveAdjustLogFiles(array $filters)
    {
        $start = substr($filters['date_start'] ?: $filters['register_start'], 0, 10);
        $end = substr($filters['date_end'] ?: $filters['register_end'], 0, 10);
        if ($start === '') {
            $start = date('Y-m-d');
        }
        if ($end === '') {
            $end = $start;
        }

        $startTs = strtotime($start);
        $endTs = strtotime($end);
        if ($startTs === false || $endTs === false) {
            return [];
        }
        if ($endTs < $startTs) {
            [$startTs, $endTs] = [$endTs, $startTs];
        }

        $files = [];
        $days = 0;
        for ($time = $startTs; $time <= $endTs && $days < 7; $time += 86400, $days++) {
            $file = storage_path('logs/adjustEvent-' . date('Y-m-d', $time) . '.log');
            if (file_exists($file)) {
                $files[] = $file;
            }
        }

        return $files;
    }

    protected function extractAdjustUserId($line)
    {
        if (preg_match('/"UserID":"?(\d+)"?/', $line, $matches)) {
            return (int)$matches[1];
        }
        if (preg_match('/"user_id":"?(\d+)"?/', $line, $matches)) {
            return (int)$matches[1];
        }
        return null;
    }

    protected function classifyAdjustLine($line)
    {
        if (strpos($line, 'facebook s2s response') !== false) {
            return 'success';
        }
        if (strpos($line, 'facebook s2s request') !== false) {
            return 'request';
        }
        if (strpos($line, 'facebook s2s skipped') !== false) {
            return 'skipped';
        }
        if (strpos($line, 'facebook s2s failed') !== false) {
            return 'failed';
        }
        if (strpos($line, 'enter:') !== false) {
            return 'enter';
        }
        return null;
    }

    protected function extractChannelFromCookie($userID, $user = null)
    {
        $cookieInfo = \App\Services\ApkService::loadCookie($userID, $user->FPID ?? '', $user->FF ?? '');
        if (!$cookieInfo || empty($cookieInfo['Params'])) {
            return null;
        }

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

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