#include <assert.h>
#include <iostream>
#include <memory>
#include "../common/comm.h"
#include "api.h"
#include "protocol.pb.h"
#include "../common/socket_client.h"
#include "../common/iobuffer.h"
#include "peer_connection.h"
//#include "VideoRenderer.h"
//#include "message_queue.h"
std::mutex CPeerConnection::_lock;
CPeerConnection::CPeerConnection(ChannelType type, SocketClient* d) :_client(d),_type(type)
{
	 
	_nativeHandle = nullptr;
 
	bReadyChannel=false;
 
}

CPeerConnection::~CPeerConnection()
{
	if (_nativeHandle != nullptr)
	{

	}
}
void CPeerConnection::Initialize(int32_t peer,int32_t index,int32_t MinPort,int32_t MaxPort)
{
	//20231023
	//std::lock_guard<std::mutex> l(_lock);
    _nativeHandle = mrsPeerConnectionCreate(MinPort,MaxPort);
	std::cout<<"native handle"<<_nativeHandle<<std::endl;
    if (_nativeHandle == nullptr)
	{
	//	mrsPeerConnectionClose(&_nativeHandle);

	//	_nativeHandle = nullptr;
		return;
	}
	mrsPeerConnectionRegisterConnectedCallback(_nativeHandle, &CPeerConnection::ConnectionCallBack, this);

	mrsPeerConnectionRegisterLocalSdpReadytoSendCallback(_nativeHandle,peer,index, &CPeerConnection::LocalSdpReadytoSendCallback, this);
	mrsPeerConnectionRegisterIceCandidateReadytoSendCallback(_nativeHandle,peer,index, &CPeerConnection::IceCandidateReadytoSendCallback, this);
    
	mrsPeerConnectionRegisterChannelCallback(_nativeHandle, &CPeerConnection::MessageCallback, this, nullptr, nullptr, nullptr, nullptr);
}
void CPeerConnection::Close()
{
	//20231023
	//std::lock_guard<std::mutex> l(_lock);
	if(_nativeHandle==nullptr) return;
	bReadyChannel = false;
	mrsPeerConnectionRegisterConnectedCallback(_nativeHandle, nullptr, nullptr);

	mrsPeerConnectionRegisterLocalSdpReadytoSendCallback(_nativeHandle,0,0, nullptr, nullptr);
	mrsPeerConnectionRegisterIceCandidateReadytoSendCallback(_nativeHandle,0, 0,nullptr, nullptr);
	 
	mrsPeerConnectionRemoveDataChannel(_nativeHandle);
 	mrsPeerConnectionClose(&_nativeHandle);
	 _nativeHandle=nullptr;
}

void CPeerConnection::AddDataChannel(bool ordered, bool reliable)
{
	mrsPeerConnectionAddDataChannel(_nativeHandle, ordered, reliable);
}
void CPeerConnection::RemoveDataChannel()
{
	mrsPeerConnectionRemoveDataChannel(_nativeHandle);
}
void CPeerConnection::ConnectionCallBack(void* UserData)
{
	CPeerConnection* lhs = static_cast<CPeerConnection*>(UserData);
	lhs->OnConnect();
}
void CPeerConnection::OnConnect()
{
	bConnected = true;
	printf("connect-------------------------------------------------\n");

}
const std::string  kOffer = "offer";
const std::string kAnswer = "answer";
void CPeerConnection::LocalSdpReadytoSendCallback(void* user_data,int32_t peer,int32_t view, const char* type, const char* sdp_data)
{
	auto lhs = static_cast<CPeerConnection*>(user_data);
	lhs->OnLocalSdpReadytoSend(peer,view,type, sdp_data);
}
void CPeerConnection::OnLocalSdpReadytoSend(int32_t peer,int32_t view,const char* type, const char* sdp)
{
	 printf ("on local sdp ready to send");
	//  std::cout << "local sdp " << sdp << std::endl;
	//std::string newsdp = ForceSdpCodecs(sdp, PreferredAudioCodec, PreferredAudioCodecExtraParamsRemote, PreferredVideoCodec, PreferredVideoCodecExtraParamsRemote);
	//std::cout<<type<<","<<__LINE__<<std::endl;
	
	if (kOffer == type)
	{
		_client->WriteOffer(peer,view, type, sdp);
	}
	else if(kAnswer==type)
	{
		
		_client->WriteAnswer(peer,view, type, sdp);
	}
	//mrsWe
}

// #include <sstream>
// void CPeerConnection::OnLocalSdpReadytoSend(int32_t peer, int32_t view, const char* type, const char* sdp)
// {
//     std::cout << "sdp " << sdp << std::endl;
//     std::cout << "-------------------------------------------" << std::endl;

//     // 解析 SDP 字符串
//     std::istringstream iss(sdp);
//     std::string line;
//     while (std::getline(iss, line))
//     {
//         // 检查是否为编码格式定义行
//         if (line.find("a=rtpmap:") == 0)
//         {
//             // 从行中提取编码格式信息
//             std::string token;
//             std::istringstream lineiss(line);
//             lineiss >> token; // "a=rtpmap:"
//             lineiss >> token; // 编码负载类型
//             lineiss >> token; // 编码名称
//             lineiss >> token; // 采样率

//             std::cout << "Supported codec: " << token << std::endl;
//         }
//     }

//     if (kOffer == type)
//     {
//         _client->WriteOffer(peer, view, type, sdp);
//     }
//     else if (kAnswer == type)
//     {
//         _client->WriteAnswer(peer, view, type, sdp);
//     }
// }


void CPeerConnection::SetRemoteDescription(const char* type, std::string sdp)
{
	printf("set remote Description\n");
	std::cout << "sdp: " << sdp.c_str()  << std::endl;
	std::cout << "TYPE: " << &type << std::endl;
	//std::string newsdp = ForceSdpCodecs(sdp, PreferredAudioCodec, PreferredAudioCodecExtraParamsLocal, PreferredVideoCodec, PreferredVideoCodecExtraParamsLocal);
	auto ret = mrsPeerConnectionSetRemoteDescription(_nativeHandle, type, sdp.c_str());

	assert(ret == true);

}

void CPeerConnection::IceCandidateReadytoSendCallback(void* user_data,int32_t peer,int32_t index, const char* sdp, int32_t sdp_mline_index, const char* sdp_mid)
{
	printf("ice candidate ready to send callback\n");
	auto lhs = static_cast<CPeerConnection*>(user_data);
	lhs->OnIceCandidateReadytoSend(peer,index,sdp, sdp_mline_index, sdp_mid);
}
void CPeerConnection::OnIceCandidateReadytoSend(int32_t peer,int32_t index,const char* candidate, int32_t sdp_mline_index, const char* sdp_mid)
{
	printf("OnIceCandidateReadytoSend\n");

	_client->WriteCandidate(peer,index, candidate, sdp_mline_index, sdp_mid);
	 
}
void CPeerConnection::AddIceCandidate(const char* sdp, int32_t sdp_mline_index, const char* sdp_mid)
{
	printf("AddIceCandidate\n");

	auto ret = mrsPeerConnectionAddIceCandidate(_nativeHandle, sdp, sdp_mline_index, sdp_mid);
	assert(ret == true);
}
bool CPeerConnection::CreateOffer()
{
//	std::cout<<__FUNCTION__<<","<<__LINE__<<std::endl;
	printf("CREATE OFFER\n");
	auto ret = mrsPeerConnectionCreateOffer(_nativeHandle);// == mrsResult::kSuccess;
	assert(ret == true);
	return true;
}

bool CPeerConnection::CreateAnswer()
{
	printf("CREATE Answer\n");

	//std::cout<<__FUNCTION__<<","<<__LINE__<<std::endl;
	auto ret = mrsPeerConnectionCreateAnswer(_nativeHandle); ;
	assert(ret == true);
	return true;
}

void CPeerConnection::AddLocalArgb32VideoFrameReady(PeerConnectionARGBVideoFrameCallback fn, void* user_data)
{
	mrsPeerConnectionRegisterARGBLocalVideoFrameCallback(_nativeHandle, fn, user_data);
}
void CPeerConnection::AddLocalAudioTrack()
{
	mrsPeerConnectionAddLocalAudioTrack(_nativeHandle);
}
void CPeerConnection::RemoveLocalAudioTrack()
{
	mrsPeerConnectionRemoveLocalAudioTrack(_nativeHandle);
}
void CPeerConnection::AddRemoteArgb32VideoFrameReady(PeerConnectionARGBVideoFrameCallback fn, void* user_data)
{
	mrsPeerConnectionRegisterARGBRemoteVideoFrameCallback(_nativeHandle, fn, user_data);
}
 
#ifdef WEBRTC_LINUX
void CPeerConnection::AddLocalVideoTrack(RenderPosition type,int32_t index)
{	
	printf("add local video track--------\n");
	 //PeerConnectionHandle peerHandle, CaptureType type, int32_t fps)
     auto ret=mrsPeerConnectionAddLocalVideoTrack(_nativeHandle, type,index);
}
 
void CPeerConnection::SwitchCapture(bool front)
{
	if(_nativeHandle!=nullptr)
		mrsPeerConnectionSwitchCapture(_nativeHandle, front);
}
void CPeerConnection::SetOtherCtx(void * data)
{
    mrsPeerConnectionSetCtx(_nativeHandle,data);
}
void * CPeerConnection::GetCurrentCtx()
{
	return mrsPeerConnectionCurrentCtx(_nativeHandle);
}
#else
void CPeerConnection::SetDataReady()
{
	bReadyChannel = true;
}
bool CPeerConnection::IsDataReady()
{
	return bReadyChannel;
}
#endif
void  CPeerConnection::MessageCallback(void * user_data,const void * data,const int32_t size)
{
    CPeerConnection* lhs=static_cast<CPeerConnection*>(user_data);
	lhs->OnPeerMessage(data,size);
	
}
void CPeerConnection::OnPeerMessage(const void * data,const int32_t size)
{
	 if(size<MessageHead::Size()) return;
     MessageHead Head;
     int8_t* Data=(int8_t *)data;
     Head.Deserialize(Data);
     if(size<MessageHead::Size()+Head.Length) return;
     auto ptr=Data+MessageHead::Size();
	 if(Head.Command==RemoNet::CC_ASKDATACHANNEL)
	 {
		 
			bReadyChannel=true;
			//return;
	 }
	 if(!bReadyChannel) return;
	  _client->OnPeerMessage(_type,Head.Command,Head.Length,ptr);
	 
	  
}

void CPeerConnection::SendData(CIOBuffer& pBuffer)
{
	if(!bReadyChannel) return;
 
	auto ret=mrsPeerConnectionSendDataChannelMessage(_nativeHandle,pBuffer.Buffer,pBuffer.Length);

	if(ret==false)
	{
		printf("send failed  to Peer \n");
	}
}