<?php


namespace app\listener\chat;

use app\services\chat\SessionService;
use app\services\chat\AssignService;
use app\models\chat\ChatSession;
use think\facade\Db;
use think\swoole\WebSocket;

/**
 * 聊天连接监听器
 * 处理: chat.connect, chat.ping, 断开连接
 * Class ChatConnectListener
 * @package app\listener\chat
 */
class ChatConnectListener
{
    private $sessionService;
    private $assignService;

    // 约束参数 (specs.md CC-10~CC-13)
    private const HEARTBEAT_INTERVAL = 30;  // 心跳间隔30秒
    private const OFFLINE_TIMEOUT = 60;     // 离线判定60秒

    public function __construct()
    {
        $this->sessionService = new SessionService();
        $this->assignService = new AssignService();
    }

    /**
     * 处理聊天连接事件
     */
    public function onConnect($ws, $event)
    {
        // 添加更详细的调试日志
        echo "[Chat] ========== 收到chat.connect事件 ==========\n";
        echo "[Chat] 原始数据: " . json_encode($data, JSON_UNESCAPED_UNICODE) . "\n";

        $token = $event['token'] ?? '';
        $source = (int)($event['source'] ?? ChatSession::SOURCE_PC);
        $role = $event['role'] ?? 'user'; // user 或 agent

        echo "[Chat] 解析后 - Token: {$token}, Source: {$source}, Role: {$role}\n";

        if ($role === 'agent') {
            $this->handleAgentConnect($ws, $token, $event);
        } else {
            $this->handleUserConnect($ws, $token, $source);
        }
    }

    /**
     * 处理用户连接
     */
    private function handleUserConnect($ws, $token, $source)
    {
        $fd = $ws->getSender();

        // 调试日志
        echo "[Chat] 收到用户连接请求 - FD: {$fd}, Token: {$token}, Source: {$source}\n";

        // 验证用户Token
        $user = $this->verifyUserToken($token);
        if (!$user) {
            echo "[Chat] Token验证失败 - Token: {$token}\n";

            // 尝试查询数据库看看是否有这个token
            $count = Db::name('user')->where('login_token', $token)->count();
            echo "[Chat] 数据库中login_token={$token}的记录数: {$count}\n";

            $ws->emit('chat.connected', [
                'success' => false,
                'error' => 'invalid_token'
            ]);
            return;
        }

        $userId = (int)$user['id'];
        echo "[Chat] Token验证成功 - UserID: {$userId}, Username: {$user['username']}\n";

        // 注册连接
        $this->sessionService->registerUserConnection($userId, $fd);

        // 保存fd映射
        $tableFd = app('swoole.table.fd');
        $tableFd->set((string)$fd, [
            'mode' => 'chat_user',
            'user_id' => $userId,
            'table_id' => 0,
            'scan_appid' => '',
            'api_appid' => '',
        ]);

        // 加入聊天房间
        $ws->join('chat_user_' . $userId);

        // 获取或创建会话
        $session = $this->sessionService->createSession($userId, $source);
        echo "[Chat] 会话创建成功 - SessionID: {$session['id']}, Status: {$session['status']}\n";

        // 获取客服信息
        $agentInfo = null;
        if (!empty($session['admin_id'])) {
            $admin = Db::name('admin')->where('id', $session['admin_id'])->find();
            $agentInfo = [
                'id' => $admin['id'],
                'nickname' => $admin['nickname'] ?? $admin['username'] ?? '客服',
            ];
        }

        $ws->emit('chat.connected', [
            'success' => true,
            'sessionId' => $session['id'],
            'status' => $session['status'],
            'agentInfo' => $agentInfo,
        ]);
        echo "[Chat] 发送chat.connected响应成功\n";

        // 如果会话待分配，通知用户
        if ($session['status'] === ChatSession::STATUS_PENDING) {
            $ws->emit('chat.offline_notice', [
                'message' => '当前客服繁忙，请稍候...'
            ]);
        }
    }

    /**
     * 处理客服连接
     */
    private function handleAgentConnect($ws, $token, $event)
    {
        $fd = $ws->getSender();

        // 验证客服Token (复用Admin Session)
        $admin = $this->verifyAdminToken($token);
        if (!$admin) {
            $ws->emit('chat.connected', [
                'success' => false,
                'error' => 'invalid_token'
            ]);
            return;
        }

        $adminId = (int)$admin['id'];
        $maxSessions = (int)($event['maxSessions'] ?? 10);

        // 注册连接
        $this->sessionService->registerAgentConnection($adminId, $fd);

        // 设置客服在线
        $this->assignService->setAgentOnline($adminId);

        // 保存fd映射
        $tableFd = app('swoole.table.fd');
        $tableFd->set((string)$fd, [
            'mode' => 'chat_agent',
            'user_id' => $adminId,
            'table_id' => 0,
            'scan_appid' => '',
            'api_appid' => '',
        ]);

        // 加入客服房间
        $ws->join('chat_agent_' . $adminId);

        // 处理离线队列
        $processed = $this->assignService->processOfflineQueue($adminId);

        // 获取当前会话列表
        $sessions = $this->sessionService->getAgentSessions($adminId);

        $ws->emit('chat.connected', [
            'success' => true,
            'sessions' => $sessions,
            'processedFromQueue' => count($processed),
        ]);

        // 通知被分配的用户
        foreach ($processed as $item) {
            $this->notifyUserAssigned($item['userId'], $item['sessionId'], $adminId);
        }
    }

    /**
     * 处理心跳
     */
    public function onPing($ws, $event)
    {
        $fd = $ws->getSender();
        $tableFd = app('swoole.table.fd');
        $fdInfo = $tableFd->get((string)$fd);

        if (!$fdInfo) {
            return;
        }

        if ($fdInfo['mode'] === 'chat_user') {
            $this->sessionService->refreshUserConnection($fdInfo['user_id']);
        } elseif ($fdInfo['mode'] === 'chat_agent') {
            $this->sessionService->refreshAgentConnection($fdInfo['user_id']);
            $this->assignService->refreshAgentOnline($fdInfo['user_id']);
        }

        $ws->emit('chat.pong', []);
    }

    /**
     * 处理断开连接
     */
    public function onClose($ws)
    {
        $fd = $ws->getSender();
        $tableFd = app('swoole.table.fd');
        $fdInfo = $tableFd->get((string)$fd);

        if (!$fdInfo) {
            return;
        }

        if ($fdInfo['mode'] === 'chat_user') {
            $userId = $fdInfo['user_id'];
            $this->sessionService->clearUserConnection($userId);
            $ws->leave('chat_user_' . $userId);
        } elseif ($fdInfo['mode'] === 'chat_agent') {
            $adminId = $fdInfo['user_id'];
            $this->sessionService->clearAgentConnection($adminId);
            $this->assignService->setAgentOffline($adminId);
            $ws->leave('chat_agent_' . $adminId);
        }
    }

    /**
     * 验证用户Token
     */
    private function verifyUserToken(string $token): ?array
    {
        if (empty($token)) {
            echo "[Chat] Token为空\n";
            return null;
        }

        // 去除token末尾可能的空格
        $token = trim($token);

        echo "[Chat] 开始验证Token: {$token}\n";

        $user = Db::name('user')
            ->where('login_token', $token)
            ->where('status', 1)
            ->where('is_delete', 0)
            ->find();

        if ($user) {
            echo "[Chat] 找到用户: ID={$user['id']}, Username={$user['username']}\n";
        } else {
            echo "[Chat] 未找到匹配的用户\n";
        }

        return $user;
    }

    /**
     * 验证客服Token
     */
    private function verifyAdminToken(string $token): ?array
    {
        if (empty($token)) {
            return null;
        }

        // 复用Admin的session token验证
        return Db::name('admin')
            ->where('login_token', $token)
            ->where('status', 1)
            ->find();
    }

    /**
     * 通知用户会话已分配
     */
    private function notifyUserAssigned($userId, $sessionId, $adminId)
    {
        $ws = app('\think\swoole\WebSocket');
        $admin = Db::name('admin')->where('id', $adminId)->find();

        $ws->to('chat_user_' . $userId)->emit('chat.session.assigned', [
            'sessionId' => $sessionId,
            'agentInfo' => [
                'id' => $admin['id'],
                'nickname' => $admin['nickname'] ?? $admin['username'] ?? '客服',
            ],
        ]);
    }
}
