#include "websocket_protocol.h"
#include "board.h"
#include "system_info.h"
#include "application.h"
#include "background_task.h"

#include <cstring>
#include <cJSON.h>
#include <esp_log.h>
#include <arpa/inet.h>
#include <atomic>
#include "assets/lang_config.h"

#define TAG "WS"

// 初始化静态成员
std::atomic<int> WebsocketProtocol::pending_delete_tasks_{0};

WebsocketProtocol::WebsocketProtocol() {
    event_group_handle_ = xEventGroupCreate();
}

WebsocketProtocol::~WebsocketProtocol() {
    if (websocket_ != nullptr) {
        delete websocket_;
    }
    vEventGroupDelete(event_group_handle_);
}

void WebsocketProtocol::Start() {
}

void WebsocketProtocol::SendAudio(const std::vector<uint8_t>& data) {
    if (websocket_ == nullptr || !websocket_->IsConnected()) {
        ESP_LOGD(TAG, "WebSocket not connected, dropping audio data");
        return;
    }

    websocket_->Send(data.data(), data.size(), true);
}

void WebsocketProtocol::SendText(const std::string& text) {
    // 🔧 修复：增强连接状态检查，防止访问无效连接
    if (websocket_ == nullptr) {
        ESP_LOGD(TAG, "WebSocket is null, dropping text message: %s", text.c_str());
        return;
    }
    
    // 🔧 双重检查连接状态，防止偶发性连接异常
    if (!websocket_->IsConnected()) {
        ESP_LOGD(TAG, "WebSocket not connected, dropping text message: %s", text.c_str());
        return;
    }
    
    // 🔧 再次验证连接有效性（防止偶发性TLS状态异常）
    if (!IsAudioChannelOpened()) {
        ESP_LOGW(TAG, "Audio channel not properly opened, dropping message: %s", text.c_str());
        return;
    }

    // 🔧 添加异常处理，防止TLS层崩溃
    try {
        // 验证消息内容有效性
        if (text.empty()) {
            ESP_LOGW(TAG, "Attempted to send empty message");
            return;
        }
        
        if (!websocket_->Send(text)) {
            ESP_LOGE(TAG, "Failed to send text: %s", text.c_str());
            SetError(Lang::Strings::SERVER_ERROR);
        } else {
            ESP_LOGD(TAG, "Successfully sent WebSocket message: %s", text.c_str());
        }
    } catch (const std::exception& e) {
        ESP_LOGE(TAG, "Exception sending text: %s, message: %s", e.what(), text.c_str());
        SetError(Lang::Strings::SERVER_ERROR);
    } catch (...) {
        ESP_LOGE(TAG, "Unknown exception sending text: %s", text.c_str());
        SetError(Lang::Strings::SERVER_ERROR);
    }
}

bool WebsocketProtocol::IsAudioChannelOpened() const {
    if (websocket_ == nullptr) {
        return false;
    }
    
    // 🔧 增强连接状态验证：不仅检查IsConnected，还验证实际可用性
    bool basic_check = websocket_->IsConnected() && !error_occurred_ && !IsTimeout();
    
    if (!basic_check) {
        return false;
    }
    
    // 🔧 额外验证：确保WebSocket真正可用（偶发性保护）
    try {
        // 这里可以添加轻量级的连接测试，但要避免频繁调用
        return true;
    } catch (...) {
        ESP_LOGW(TAG, "WebSocket connection validation failed");
        return false;
    }
}

void WebsocketProtocol::CloseAudioChannel() {
    std::lock_guard<std::mutex> lock(websocket_mutex_);
    if (websocket_ != nullptr && !is_being_deleted_) {
        // ESP_LOGI(TAG, "🔧 关闭WebSocket连接");
        is_being_deleted_ = true;
        
        try {
            websocket_->Close();
        } catch (const std::exception& e) {
            ESP_LOGE(TAG, "WebSocket close failed: %s", e.what());
        }
        
        auto websocket_to_delete = websocket_;
        websocket_ = nullptr;  // 立即置空，防止重复访问
        
        // 使用更安全的延迟进行异步删除，确保其他线程完成访问
        Application::GetInstance().Schedule([this, websocket_to_delete]() {
            vTaskDelay(pdMS_TO_TICKS(50));
            try {
                delete websocket_to_delete;
                ESP_LOGI(TAG, "🔧 WebSocket已安全删除");
            } catch (const std::exception& e) {
                ESP_LOGE(TAG, "WebSocket deletion failed: %s", e.what());
            }
            is_being_deleted_ = false;
        });
    }
}

bool WebsocketProtocol::OpenAudioChannel() {
    std::lock_guard<std::mutex> lock(websocket_mutex_);
    if (websocket_ != nullptr && !is_being_deleted_) {
        // ESP_LOGI(TAG, "🔧 关闭现有WebSocket连接");
        is_being_deleted_ = true;
        
        try {
            // 🔧 关键修复：清除OnDisconnected回调，防止触发OnAudioChannelClosed
            websocket_->OnDisconnected(nullptr);
            websocket_->Close();
        } catch (const std::exception& e) {
            ESP_LOGE(TAG, "WebSocket close failed during reopen: %s", e.what());
        }
        
        auto websocket_to_delete = websocket_;
        websocket_ = nullptr;  // 立即置空，防止重复访问
        
        // 增加待删除任务计数
        pending_delete_tasks_++;
        
        // 使用更安全的异步删除机制
        Application::GetInstance().Schedule([this, websocket_to_delete]() {
            vTaskDelay(pdMS_TO_TICKS(200));  // 增加延迟到200ms
            try {
                delete websocket_to_delete;
                ESP_LOGI(TAG, "🔧 旧WebSocket已安全删除，剩余待删除任务: %d", pending_delete_tasks_.load() - 1);
            } catch (const std::exception& e) {
                ESP_LOGE(TAG, "WebSocket deletion failed: %s", e.what());
            }
            pending_delete_tasks_--;  // 减少计数
            is_being_deleted_ = false;
        });
        
        // 短暂延迟让删除任务启动
        vTaskDelay(pdMS_TO_TICKS(150));
    }
    
    // 如果有太多待删除任务，等待一下
    if (pending_delete_tasks_.load() > 2) {
        ESP_LOGW(TAG, "⚠️ 检测到多个待删除任务 (%d)，等待清理完成", pending_delete_tasks_.load());
        int wait_count = 0;
        while (pending_delete_tasks_.load() > 1 && wait_count < 10) {
            vTaskDelay(pdMS_TO_TICKS(100));
            wait_count++;
        }
    }

    error_occurred_ = false;
    std::string url = CONFIG_WEBSOCKET_URL;
    std::string token = "Bearer " + std::string(CONFIG_WEBSOCKET_ACCESS_TOKEN);
    
    // 🔧 添加内存检查和错误处理
    try {
        websocket_ = Board::GetInstance().CreateWebSocket();
        if (websocket_ == nullptr) {
            ESP_LOGE("WebsocketProtocol", "Failed to create WebSocket - out of memory");
            return false;
        }
    } catch (const std::exception& e) {
        ESP_LOGE("WebsocketProtocol", "Exception creating WebSocket: %s", e.what());
        return false;
    } catch (...) {
        ESP_LOGE("WebsocketProtocol", "Unknown exception creating WebSocket");
        return false;
    }
    websocket_->SetHeader("Authorization", token.c_str());
    websocket_->SetHeader("Protocol-Version", "1");
    websocket_->SetHeader("Device-Id", SystemInfo::GetMacAddress().c_str());
    websocket_->SetHeader("Client-Id", Board::GetInstance().GetUuid().c_str());

    websocket_->OnData([this](const char* data, size_t len, bool binary) {
        if (binary) {
            if (on_incoming_audio_ != nullptr) {
 

                on_incoming_audio_(std::vector<uint8_t>((uint8_t*)data, (uint8_t*)data + len));// 接收音频数据
            }
        } else {
            // Parse JSON data
            auto root = cJSON_Parse(data);
            
            // 添加调试日志：打印接收到的原始JSON数据
            ESP_LOGI(TAG, "🔍 接收到JSON数据: %s", data);
            
            // 添加调试日志：解析JSON结构
            if (root == NULL) {
                ESP_LOGE(TAG, "❌ JSON解析失败，数据格式错误");
                return;
            }
            
            // 打印JSON对象的所有字段
            char* json_string = cJSON_Print(root);
            if (json_string != NULL) {
                ESP_LOGI(TAG, "📋 解析后的JSON结构: %s", json_string);
                free(json_string);
            }
            
            auto type = cJSON_GetObjectItem(root, "type");//
           
            if (type != NULL) {
                ESP_LOGI(TAG, "📝 消息类型: %s", type->valuestring);
                if (strcmp(type->valuestring, "hello") == 0) {// 接收服务器hello消息
                    ParseServerHello(root);// 解析服务器hello消息
                } else {
                    if (on_incoming_json_ != nullptr) {// 接收服务器其他消息
                        on_incoming_json_(root);// 调用回调函数处理其他消息
                    }
                }
            } else {
                ESP_LOGE(TAG, "缺少消息类型, data: %s", data);// 缺少消息类型
            }
            cJSON_Delete(root);
        }
        last_incoming_time_ = std::chrono::steady_clock::now();
    });

    websocket_->OnDisconnected([this]() {
        ESP_LOGI(TAG, "Websocket disconnected");
        
        // 立即停止音频处理，防止崩溃
        auto& app = Application::GetInstance();
#if CONFIG_USE_AUDIO_PROCESSOR
        app.StopAudioProcessor();
        ESP_LOGI(TAG, "Audio processor stopped immediately");
#endif
        
        if (on_audio_channel_closed_ != nullptr) {
            on_audio_channel_closed_();
        }
    });

    if (!websocket_->Connect(url.c_str())) {
        ESP_LOGE(TAG, "Failed to connect to websocket server");
        SetError(Lang::Strings::SERVER_NOT_FOUND);
        return false;
    }

    // Send hello message to describe the client
    // keys: message type, version, audio_params (format, sample_rate, channels)
    std::string message = "{";
    message += "\"type\":\"hello\",";
    message += "\"version\": 1,";
    message += "\"transport\":\"websocket\",";
    message += "\"audio_params\":{";
    message += "\"format\":\"opus\", \"sample_rate\":16000, \"channels\":1, \"frame_duration\":" + std::to_string(OPUS_FRAME_DURATION_MS);
    message += "}}";
    websocket_->Send(message);

    // Wait for server hello
    EventBits_t bits = xEventGroupWaitBits(event_group_handle_, WEBSOCKET_PROTOCOL_SERVER_HELLO_EVENT, pdTRUE, pdFALSE, pdMS_TO_TICKS(10000));
    if (!(bits & WEBSOCKET_PROTOCOL_SERVER_HELLO_EVENT)) {
        ESP_LOGE(TAG, "Failed to receive server hello");
        SetError(Lang::Strings::SERVER_TIMEOUT);
        return false;
    }

    if (on_audio_channel_opened_ != nullptr) {
        on_audio_channel_opened_();
    }

    return true;
}

void WebsocketProtocol::ParseServerHello(const cJSON* root) {
    auto transport = cJSON_GetObjectItem(root, "transport");
    if (transport == nullptr || strcmp(transport->valuestring, "websocket") != 0) {
        ESP_LOGE(TAG, "Unsupported transport: %s", transport->valuestring);
        return;
    }

    auto audio_params = cJSON_GetObjectItem(root, "audio_params");
    if (audio_params != NULL) {
        auto sample_rate = cJSON_GetObjectItem(audio_params, "sample_rate");
        if (sample_rate != NULL) {
            server_sample_rate_ = sample_rate->valueint;
        }
        auto frame_duration = cJSON_GetObjectItem(audio_params, "frame_duration");
        if (frame_duration != NULL) {
            server_frame_duration_ = frame_duration->valueint;
        }
    }

    xEventGroupSetBits(event_group_handle_, WEBSOCKET_PROTOCOL_SERVER_HELLO_EVENT);
}