#include "websocketclient.h"

#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonParseError>
#include <QUrl>
#include <QUrlQuery>

#include "networkaccessmanager.h"

#include <appevent.h>

WebSocketClient::WebSocketClient(QObject* parent)
    : QObject(parent)
    , m_connected(false)
    , m_autoReconnect(true)
    , m_reconnectAttempts(0)
    , m_maxReconnectAttempts(300)
    , m_isReconnecting(false)
{
    // 连接WebSocket信号
    connect(&m_webSocket, &QWebSocket::connected, this, &WebSocketClient::onConnected);
    connect(&m_webSocket, &QWebSocket::disconnected, this, &WebSocketClient::onDisconnected);
    connect(&m_webSocket,
            &QWebSocket::textMessageReceived,
            this,
            &WebSocketClient::onTextMessageReceived);
    connect(&m_webSocket,
            QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error),
            this,
            &WebSocketClient::onError);

    // 设置心跳包定时器
    connect(&m_pingTimer, &QTimer::timeout, this, &WebSocketClient::sendPing);
    m_pingTimer.setInterval(30000); // 30秒发送一次心跳

    // 设置重连定时器
    m_reconnectTimer.setSingleShot(true);
    connect(&m_reconnectTimer, &QTimer::timeout, this, &WebSocketClient::tryReconnect);
}

WebSocketClient::~WebSocketClient()
{
    disconnect();
}

void WebSocketClient::connectToRoom(const QString& roomId)
{
    if (m_connected) {
        disconnect();
    }

    m_roomId = roomId;
    m_reconnectAttempts = 0; // 重置重连尝试次数

    QUrl url = buildWebSocketUrl(roomId);
    qDebug() << "connectToRoom" << url;
    // 设置请求头
    QNetworkRequest request(url);
    const QString token = AppEvent::instance()->jwtToken();
    if (!token.isEmpty()) {
        request.setRawHeader("Authorization", "Bearer " + token.toUtf8());
    }

    qDebug() << "---" << token;

    request.setRawHeader("Machine-Code", AppEvent::instance()->machineCode().toUtf8());
    request.setRawHeader("Accept-Language", AppEvent::instance()->locale().toUtf8());

    // 连接WebSocket
    m_webSocket.open(request);
}

void WebSocketClient::disconnect()
{
    m_autoReconnect = false; // 禁用自动重连
    m_reconnectTimer.stop(); // 停止重连定时器

    if (m_connected) {
        m_pingTimer.stop();
        m_webSocket.close();
        m_connected = false;
        emit connectionStateChanged(false);
    }
}

void WebSocketClient::sendMessage(const QString& content, const QString& type)
{
    if (!m_connected) {
        emit errorOccurred("未连接到聊天室，无法发送消息");
        return;
    }

    QJsonObject message;
    message["content"] = content;
    message["type"] = type;
    message["roomId"] = m_roomId;
    message["time"] = QDateTime::currentDateTime().toUTC().toString(Qt::ISODate);

    QJsonDocument doc(message);
    m_webSocket.sendTextMessage(doc.toJson(QJsonDocument::Compact));
}

bool WebSocketClient::isConnected() const
{
    return m_connected;
}

void WebSocketClient::onConnected()
{
    m_connected = true;
    m_isReconnecting = false;
    m_reconnectAttempts = 0; // 连接成功后重置重连计数
    m_pingTimer.start();
    emit connectionStateChanged(true);
}

void WebSocketClient::onDisconnected()
{
    m_connected = false;
    m_pingTimer.stop();
    emit connectionStateChanged(false);

    // 如果启用了自动重连，且当前不在重连过程中，则尝试重连
    if (m_autoReconnect && !m_roomId.isEmpty() && !m_isReconnecting) {
        qDebug() << "WebSocket断开连接，准备重连...";
        // 使用指数退避策略，每次重连间隔时间增加
        int reconnectDelay = 1000 * (1 << qMin(m_reconnectAttempts, 5)); // 最大延迟32秒
        m_reconnectTimer.start(reconnectDelay);
    }
}

void WebSocketClient::onTextMessageReceived(const QString& message)
{
    QJsonParseError error;
    QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8(), &error);

    if (error.error != QJsonParseError::NoError) {
        emit errorOccurred("解析消息失败: " + error.errorString());
        return;
    }

    if (doc.isObject()) {
        QJsonObject obj = doc.object();

        qDebug() << "----------------------------->" << obj;
        // 处理心跳响应
        if (obj.contains("type") && obj["type"].toString() == "pong") {
            return;
        }

        // 处理聊天消息
        ChatMessage chatMessage;
        const QString type = obj["type"].toString();
        const QString content = obj["content"].toString();

        // 设置消息类型
        if (type == "room") {
            chatMessage.type = MessageType::Left;
        } else if (type == "system") {
            chatMessage.type = MessageType::System;
        } else if (type == "private") {
            chatMessage.type = MessageType::Right;
        } else if (type == "ping") {
            return;
        } else if (type == "room_live_status") {
            emit liveStatus(content);
            return;
        } else if (type == "stats_update") {
            emit statsUpdate(obj);
            return;
        }

        // 设置消息内容
        chatMessage.text = content;
        chatMessage.senderName = obj["fromUserName"].toString();

        // 设置时间（如果服务器提供）
        if (obj.contains("time") && !obj["time"].toString().isEmpty()) {
            QDateTime msgTime = QDateTime::fromString(obj["time"].toString(), Qt::ISODate);
            if (msgTime.isValid()) {
                chatMessage.timestamp = msgTime;
            } else {
                chatMessage.timestamp = QDateTime::currentDateTime();
            }
        } else {
            chatMessage.timestamp = QDateTime::currentDateTime();
        }

        // 设置发送者ID（如果服务器提供）
        // if (obj.contains("senderId")) {
        //     chatMessage.senderId = obj["senderId"].toString();
        // }

        emit messageReceived(chatMessage);
    }
}

void WebSocketClient::onError(QAbstractSocket::SocketError error)
{
    Q_UNUSED(error);
    emit errorOccurred("WebSocket错误: " + m_webSocket.errorString());

    // 错误发生时不需要额外处理，因为错误通常会触发disconnected信号，
    // 在onDisconnected中已经处理了重连逻辑
}

void WebSocketClient::sendPing()
{
    if (m_connected) {
        QJsonObject pingMessage;
        pingMessage["type"] = "ping";
        pingMessage["time"] = QDateTime::currentDateTime().toString(Qt::ISODate);
        QJsonDocument doc(pingMessage);
        m_webSocket.sendTextMessage(doc.toJson(QJsonDocument::Compact));
    }
}

QUrl WebSocketClient::buildWebSocketUrl(const QString& roomId)
{
    // 从HTTP URL构建WebSocket URL
    QString baseUrl = TC::RequestClient::globalInstance()->baseUrl();

    // 将http(s)://替换为ws(s)://
    QString wsUrl = baseUrl;
    if (wsUrl.startsWith("https://")) {
        wsUrl.replace(0, 8, "wss://");
    } else if (wsUrl.startsWith("http://")) {
        wsUrl.replace(0, 7, "ws://");
    }

    if (wsUrl.isEmpty()) {
        wsUrl = "ws://127.0.0.1:8200";
    }

    // 构建完整的WebSocket URL
    return QUrl(wsUrl + "/api/ws/chat/" + roomId);
}

void WebSocketClient::tryReconnect()
{
    // 防止重复进入重连流程
    if (m_isReconnecting || !m_autoReconnect || m_roomId.isEmpty() || m_connected) {
        return;
    }

    m_isReconnecting = true;
    m_reconnectAttempts++;

    if (m_reconnectAttempts <= m_maxReconnectAttempts) {
        qDebug() << "尝试重新连接WebSocket，第" << m_reconnectAttempts << "次尝试...";
        emit reconnecting(m_reconnectAttempts, m_maxReconnectAttempts);

        // 确保WebSocket处于关闭状态
        if (m_webSocket.state() != QAbstractSocket::UnconnectedState) {
            m_webSocket.abort();
            QTimer::singleShot(500, this, &WebSocketClient::doReconnect);
        } else {
            doReconnect();
        }
    } else {
        qDebug() << "WebSocket重连失败，已达到最大尝试次数";
        emit reconnectFailed();
        m_autoReconnect = false; // 禁用自动重连
        m_isReconnecting = false;
    }
}

void WebSocketClient::doReconnect()
{
    QUrl url = buildWebSocketUrl(m_roomId);
    QNetworkRequest request(url);
    const QString token = AppEvent::instance()->jwtToken();
    if (!token.isEmpty()) {
        request.setRawHeader("Authorization", "Bearer " + token.toUtf8());
    }

    request.setRawHeader("Machine-Code", AppEvent::instance()->machineCode().toUtf8());
    request.setRawHeader("Accept-Language", AppEvent::instance()->locale().toUtf8());

    m_webSocket.open(request);

    // 添加超时保护，防止连接过程卡死
    QTimer::singleShot(10000, this, [this]() {
        if (!m_connected && m_isReconnecting) {
            qDebug() << "重连超时，中断当前连接尝试";
            m_webSocket.abort();
            m_isReconnecting = false;

            // 继续下一次重连尝试
            if (m_autoReconnect && m_reconnectAttempts < m_maxReconnectAttempts) {
                int reconnectDelay = 1000 * (1 << qMin(m_reconnectAttempts, 5));
                m_reconnectTimer.start(reconnectDelay);
            } else if (m_reconnectAttempts >= m_maxReconnectAttempts) {
                emit reconnectFailed();
                m_autoReconnect = false;
            }
        }
    });
}

void WebSocketClient::setAutoReconnect(bool enable)
{
    m_autoReconnect = enable;
}

void WebSocketClient::setMaxReconnectAttempts(int maxAttempts)
{
    m_maxReconnectAttempts = maxAttempts;
}
