<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;

/**
 * Web日志行为分析控制器
 */
class WebLogController extends Controller
{
    /**
     * 日志列表页面
     */
    public function index(Request $request)
    {
        // 获取可用日期列表
        $availableDates = $this->getAvailableDates();

        // 如果没有指定日期，使用最新的日期
        $defaultDate = !empty($availableDates) ? $availableDates[0]['value'] : date('Ymd');

        $date = $request->input('date', $defaultDate);
        $channel = $request->input('channel', '');
        $act = $request->input('act', '');
        $md5 = $request->input('md5', '');
        $ip = $request->input('ip', '');
        $page = $request->input('page', 1);
        $pageSize = $request->input('pageSize', 100); // 默认100条

        // 读取日志文件
        $logFile = storage_path("logs/{$date}_weblog.log");

        if (!File::exists($logFile)) {
            return view('admin.weblog.index', [
                'logs' => [],
                'total' => 0,
                'date' => $date,
                'channel' => $channel,
                'act' => $act,
                'md5' => $md5,
                'ip' => $ip,
                'page' => $page,
                'pageSize' => $pageSize,
                'availableDates' => $availableDates,
                'availableChannels' => [],
                'stats' => [],
                'error' => "日志文件不存在: {$date}_weblog.log"
            ]);
        }

        // 解析日志
        $logs = $this->parseLogFile($logFile, $channel, $act, $md5, $ip);

        // 标记相同IP的记录组
        $logs = $this->markIpGroups($logs);

        // 分页
        $total = count($logs);
        $logs = array_slice($logs, ($page - 1) * $pageSize, $pageSize);

        // 统计数据
        $stats = $this->getStatistics($logFile);

        // 获取可用渠道列表（从统计数据中提取）
        $availableChannels = array_keys($stats['channels']);
        sort($availableChannels);

        return view('admin.weblog.index', [
            'logs' => $logs,
            'total' => $total,
            'date' => $date,
            'channel' => $channel,
            'act' => $act,
            'md5' => $md5,
            'ip' => $ip,
            'page' => $page,
            'pageSize' => $pageSize,
            'availableDates' => $availableDates,
            'availableChannels' => $availableChannels,
            'stats' => $stats,
            'error' => null
        ]);
    }

    /**
     * 解析日志文件
     */
    private function parseLogFile($logFile, $filterChannel = '', $filterAct = '', $filterMd5 = '', $filterIp = '')
    {
        $logs = [];
        $content = File::get($logFile);

        // 按空行分割日志条目
        $entries = preg_split('/\n\n+/', $content);

        foreach ($entries as $entry) {
            if (empty(trim($entry))) continue;

            $lines = explode("\n", $entry);
            $logData = [
                'date' => '',
                'ip' => '',
                'agent' => '',
                'locale' => '',
                'referer' => '',
                'channel' => '',
                'act' => '',
                'md5' => '',
                'orderid' => '',
                'remark' => '',
                'browser' => '',
                'v' => '',
                'in_fb' => false,
                'os' => '',
                'device' => ''
            ];

            foreach ($lines as $line) {
                // 解析日期
                if (preg_match('/^date:\s*(.+)$/', $line, $matches)) {
                    $logData['date'] = trim($matches[1]);
                }

                // 解析IP和Agent
                if (preg_match('/^ip:\s*([^\s]+).*agent:(.+?)locale:(.+)$/', $line, $matches)) {
                    $logData['ip'] = trim($matches[1]);
                    $logData['agent'] = trim($matches[2]);
                    $logData['locale'] = trim($matches[3]);

                    // 分析UserAgent
                    $analysis = $this->analyzeUserAgent($logData['agent']);
                    $logData['in_fb'] = $analysis['in_fb'];
                    $logData['os'] = $analysis['os'];
                    $logData['device'] = $analysis['device'];
                }

                // 解析referer
                if (preg_match('/^referer:\s*(.+)$/', $line, $matches)) {
                    $logData['referer'] = trim($matches[1]);
                }

                // 解析content (JSON)
                if (preg_match('/^content:\s*(\{.+\})$/', $line, $matches)) {
                    $json = json_decode($matches[1], true);
                    if ($json) {
                        $logData['channel'] = $this->extractChannel($json['host'] ?? '');
                        $logData['act'] = $json['act'] ?? '';
                        $logData['md5'] = $json['md5'] ?? '';
                        $logData['orderid'] = $json['orderid'] ?? '';
                        $logData['remark'] = $json['remark'] ?? '';
                        $logData['browser'] = $json['browser'] ?? '';
                        $logData['v'] = $json['v'] ?? '';
                    }
                }
            }

            // 过滤测试人员IP
            if (strstr($logData['ip'], '116.86.210.235')) continue;

            // 筛选
            if ($filterChannel && $logData['channel'] !== $filterChannel) continue;
            if ($filterAct && $logData['act'] !== $filterAct) continue;
            if ($filterMd5 && $logData['md5'] !== $filterMd5) continue;
            if ($filterIp && $logData['ip'] !== $filterIp) continue;

            if (!empty($logData['date'])) {
                $logs[] = $logData;
            }
        }

        // 按时间正序
        usort($logs, function($a, $b) {
            return strcmp($a['date'], $b['date']);
        });

        return $logs;
    }

    /**
     * 提取渠道编号 (host最后的数字部分)
     */
    private function extractChannel($host)
    {
        if (preg_match('/_(\d+)$/', $host, $matches)) {
            return $matches[1];
        }
        return $host;
    }

    /**
     * 分析UserAgent
     */
    private function analyzeUserAgent($agent)
    {
        $result = [
            'in_fb' => false,
            'os' => 'Unknown',
            'device' => 'Unknown'
        ];

        // 检测是否在Facebook中
        if (stripos($agent, 'FBAN') !== false ||
            stripos($agent, 'FBAV') !== false ||
            stripos($agent, 'IAB') !== false ||
            stripos($agent, 'FACEBOOK') !== false ||
            stripos($agent, 'FB_IAB') !== false ||
            stripos($agent, 'FB4A') !== false) {
            $result['in_fb'] = true;
        }

        // 检测iOS设备及型号
        if (stripos($agent, 'iPhone') !== false) {
            $result['os'] = 'iOS';
            // 提取iPhone型号
            if (preg_match('/iPhone\s*(\d+[,_]\d+)?/i', $agent, $matches)) {
                if (!empty($matches[1])) {
                    $result['device'] = 'iPhone ' . str_replace(['_', ','], ['.', '.'], $matches[1]);
                } else {
                    $result['device'] = 'iPhone';
                }
            } else {
                $result['device'] = 'iPhone';
            }
            // 提取iOS版本
            if (preg_match('/OS\s+(\d+)[._](\d+)(?:[._](\d+))?/i', $agent, $matches)) {
                $result['os'] = 'iOS ' . $matches[1] . '.' . $matches[2];
            }
        } elseif (stripos($agent, 'iPad') !== false) {
            $result['os'] = 'iOS';
            $result['device'] = 'iPad';
            // 提取iOS版本
            if (preg_match('/OS\s+(\d+)[._](\d+)(?:[._](\d+))?/i', $agent, $matches)) {
                $result['os'] = 'iOS ' . $matches[1] . '.' . $matches[2];
            }
        }
        // 检测Android设备及型号
        elseif (stripos($agent, 'Android') !== false) {
            // 提取Android版本
            if (preg_match('/Android\s+([\d.]+)/i', $agent, $matches)) {
                $result['os'] = 'Android ' . $matches[1];
            } else {
                $result['os'] = 'Android';
            }

            // 提取设备型号（常见厂商）
            $deviceModel = 'Android';

            // Samsung
            if (preg_match('/SM-([A-Z0-9]+)/i', $agent, $matches)) {
                $deviceModel = 'Samsung ' . $matches[1];
            }
            // Huawei
            elseif (preg_match('/(HW-|HUAWEI\s?)([A-Z0-9\-]+)/i', $agent, $matches)) {
                $deviceModel = 'Huawei ' . $matches[2];
            }
            // Xiaomi
            elseif (preg_match('/(MI\s+|Redmi\s+|POCO\s+)([A-Z0-9\s]+)/i', $agent, $matches)) {
                $deviceModel = trim($matches[1] . $matches[2]);
            }
            // Oppo
            elseif (preg_match('/OPPO\s+([A-Z0-9]+)/i', $agent, $matches)) {
                $deviceModel = 'OPPO ' . $matches[1];
            }
            // Vivo
            elseif (preg_match('/vivo\s+([A-Z0-9]+)/i', $agent, $matches)) {
                $deviceModel = 'vivo ' . $matches[1];
            }
            // OnePlus
            elseif (preg_match('/ONEPLUS\s+([A-Z0-9]+)/i', $agent, $matches)) {
                $deviceModel = 'OnePlus ' . $matches[1];
            }
            // Google Pixel
            elseif (preg_match('/Pixel\s+([A-Z0-9\s]+)/i', $agent, $matches)) {
                $deviceModel = 'Pixel ' . trim($matches[1]);
            }
            // 其他通用匹配 - 尝试提取Build/之前的型号
            elseif (preg_match('/;\s*([A-Z0-9\-\s]+)\s+Build\//i', $agent, $matches)) {
                $model = trim($matches[1]);
                // 过滤掉Android版本号
                $model = preg_replace('/Android[\s\d.]+/i', '', $model);
                if (strlen($model) > 2 && strlen($model) < 30) {
                    $deviceModel = trim($model);
                }
            }

            $result['device'] = $deviceModel;
        }
        // Windows
        elseif (stripos($agent, 'Windows') !== false) {
            $result['device'] = 'PC';
            // 提取Windows版本
            if (preg_match('/Windows NT\s+([\d.]+)/i', $agent, $matches)) {
                $winVersion = $matches[1];
                $versionMap = [
                    '10.0' => 'Windows 10/11',
                    '6.3' => 'Windows 8.1',
                    '6.2' => 'Windows 8',
                    '6.1' => 'Windows 7',
                    '6.0' => 'Windows Vista',
                ];
                $result['os'] = $versionMap[$winVersion] ?? 'Windows NT ' . $winVersion;
            } else {
                $result['os'] = 'Windows';
            }
        }
        // macOS
        elseif (stripos($agent, 'Mac OS') !== false || stripos($agent, 'Macintosh') !== false) {
            $result['device'] = 'Mac';
            // 提取macOS版本
            if (preg_match('/Mac OS X\s+([\d_]+)/i', $agent, $matches)) {
                $version = str_replace('_', '.', $matches[1]);
                $result['os'] = 'macOS ' . $version;
            } else {
                $result['os'] = 'macOS';
            }
        }
        // Linux
        elseif (stripos($agent, 'Linux') !== false) {
            $result['os'] = 'Linux';
            $result['device'] = 'PC';
        }

        return $result;
    }

    /**
     * 标记相同IP的记录组
     * 先将日志按IP和时间窗口（5分钟）分组，然后重新排序
     * 让相同IP在时间相近的记录集中在一起显示
     */
    private function markIpGroups($logs)
    {
        if (empty($logs)) {
            return $logs;
        }

        // 第一步：将日志按IP和时间窗口分组（使用滑动窗口）
        $ipTimeGroups = [];
        $logAssigned = []; // 记录每条日志是否已被分配

        foreach ($logs as $index => $log) {
            if (isset($logAssigned[$index])) {
                continue; // 已经被分配到组中，跳过
            }

            $ip = $log['ip'];
            $time = strtotime($log['date']);

            // 创建新组
            $newGroup = [
                'ip' => $ip,
                'min_time' => $time,
                'max_time' => $time,
                'logs' => [$log]
            ];
            $logAssigned[$index] = true;

            // 查找其他相同IP且时间在5分钟内的记录
            foreach ($logs as $idx => $otherLog) {
                if (isset($logAssigned[$idx]) || $idx === $index) {
                    continue;
                }

                if ($otherLog['ip'] === $ip) {
                    $otherTime = strtotime($otherLog['date']);
                    // 检查是否在时间窗口内（与组内最小或最大时间相差5分钟内）
                    if (abs($otherTime - $newGroup['min_time']) <= 300 ||
                        abs($otherTime - $newGroup['max_time']) <= 300) {
                        $newGroup['logs'][] = $otherLog;
                        $newGroup['min_time'] = min($newGroup['min_time'], $otherTime);
                        $newGroup['max_time'] = max($newGroup['max_time'], $otherTime);
                        $logAssigned[$idx] = true;
                    }
                }
            }

            $ipTimeGroups[] = $newGroup;
        }

        // 第二步：按组的最早时间排序
        usort($ipTimeGroups, function($a, $b) {
            return $a['min_time'] - $b['min_time'];
        });

        // 第三步：重组日志，在每个组内按时间排序，并标记分隔线
        $sortedLogs = [];
        foreach ($ipTimeGroups as $index => $group) {
            // 组内按时间排序
            usort($group['logs'], function($a, $b) {
                return strcmp($a['date'], $b['date']);
            });

            // 添加组内的所有日志
            foreach ($group['logs'] as $logIndex => $log) {
                // 第一条记录且不是第一组时，添加分隔标记
                if ($logIndex === 0 && $index > 0) {
                    $log['show_separator'] = true;
                } else {
                    $log['show_separator'] = false;
                }
                $sortedLogs[] = $log;
            }
        }

        return $sortedLogs;
    }

    /**
     * 获取统计数据
     */
    private function getStatistics($logFile)
    {
        $logs = $this->parseLogFile($logFile);

        $stats = [
            'total' => count($logs),
            'channels' => [],
            'actions' => [],
            'in_fb_count' => 0,
            'os_distribution' => [],
            'unique_users_in_fb' => [],
            'unique_users_not_in_fb' => []
        ];

        foreach ($logs as $log) {
            // 渠道统计
            if (!isset($stats['channels'][$log['channel']])) {
                $stats['channels'][$log['channel']] = 0;
            }
            $stats['channels'][$log['channel']]++;

            // 行为统计
            if (!isset($stats['actions'][$log['act']])) {
                $stats['actions'][$log['act']] = 0;
            }
            $stats['actions'][$log['act']]++;

            // FB统计
            if ($log['in_fb']) {
                $stats['in_fb_count']++;
            }

            // OS统计
            if (!isset($stats['os_distribution'][$log['os']])) {
                $stats['os_distribution'][$log['os']] = 0;
            }
            $stats['os_distribution'][$log['os']]++;

            // 唯一用户（区分FB内外）
            if (!empty($log['md5'])) {
                if ($log['in_fb']) {
                    $stats['unique_users_in_fb'][$log['md5']] = true;
                } else {
                    $stats['unique_users_not_in_fb'][$log['md5']] = true;
                }
            }
        }

        // 排序
        arsort($stats['channels']);
        arsort($stats['actions']);
        arsort($stats['os_distribution']);

        $stats['unique_user_count_in_fb'] = count($stats['unique_users_in_fb']);
        $stats['unique_user_count_not_in_fb'] = count($stats['unique_users_not_in_fb']);
        $stats['unique_user_count'] = $stats['unique_user_count_in_fb'] + $stats['unique_user_count_not_in_fb'];
        unset($stats['unique_users_in_fb']);
        unset($stats['unique_users_not_in_fb']);

        return $stats;
    }

    /**
     * 获取可用日期列表
     */
    private function getAvailableDates()
    {
        $logPath = storage_path('logs');
        $files = File::glob($logPath . '/*_weblog.log');

        $dates = [];
        foreach ($files as $file) {
            $filename = basename($file);
            if (preg_match('/^(\d{8})_weblog\.log$/', $filename, $matches)) {
                $dates[] = [
                    'value' => $matches[1],
                    'label' => date('Y-m-d', strtotime($matches[1]))
                ];
            }
        }

        // 按日期倒序
        usort($dates, function($a, $b) {
            return strcmp($b['value'], $a['value']);
        });

        return $dates;
    }

    /**
     * 导出CSV
     */
    public function export(Request $request)
    {
        $date = $request->input('date', date('Ymd'));
        $channel = $request->input('channel', '');
        $act = $request->input('act', '');
        $md5 = $request->input('md5', '');
        $ip = $request->input('ip', '');

        $logFile = storage_path("logs/{$date}_weblog.log");

        if (!File::exists($logFile)) {
            return redirect()->back()->with('error', '日志文件不存在');
        }

        $logs = $this->parseLogFile($logFile, $channel, $act, $md5, $ip);

        $filename = "weblog_{$date}.csv";
        $headers = [
            'Content-Type' => 'text/csv; charset=UTF-8',
            'Content-Disposition' => "attachment; filename=\"{$filename}\"",
        ];

        $callback = function() use ($logs) {
            $file = fopen('php://output', 'w');

            // UTF-8 BOM
            fprintf($file, chr(0xEF).chr(0xBB).chr(0xBF));

            // CSV表头
            fputcsv($file, [
                '日期时间',
                '渠道',
                '行为',
                '用户ID(MD5)',
                'IP',
                '是否FB',
                '操作系统',
                '设备',
                '浏览器',
                'OrderID',
                '备注'
            ]);

            // CSV内容
            foreach ($logs as $log) {
                fputcsv($file, [
                    $log['date'],
                    $log['channel'],
                    $log['act'],
                    $log['md5'],
                    $log['ip'],
                    $log['in_fb'] ? 'Y' : 'N',
                    $log['os'],
                    $log['device'],
                    $log['browser'],
                    $log['orderid'],
                    $log['remark']
                ]);
            }

            fclose($file);
        };

        return response()->stream($callback, 200, $headers);
    }
}
