
#include "MediaClientConnection.h"
#include "MediaWebSocketService.h"
#include "MediaInfoService.h"
#include "ZWRoom.h"

namespace mfs
{
    // -3 阻塞；-1 跳过
    int MediaClientConnection::preWriteData(char* data, int dataLen)
    {
        if (_firstFrameSend)
        {
            _streamInfo.timestampStartData = std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());

            if (_streamInfo.targetType!="0")
            {
                MediaInfoService::Instance()->sendUserStart(_streamInfo);
            }
            _firstFrameSend = false;
        }
        
        if (_isPlayback && _isPause)
        {
            return -3;
        }
        int iret = preFilter((uint8_t*)data, dataLen);
        if (iret != 0)
        {
            return -1;
        }
        return 0;
    }
    int MediaClientConnection::preFilter(uint8_t* data, int len)
    {
        Rtp808HeadBaseV* head = reinterpret_cast<Rtp808HeadBaseV*>(const_cast<uint8_t*>(data));
        auto payloadType = PAYLOAD_TYPE_MASK & head->headPT;
        if (payloadType == PAYLOAD_TYPE_G726)
        {
            // G726 细分格式
            head->headPT &= (1 << 7);
            if (_audioFormat == AUDIOFORMAT_G72640)
            {
                head->headPT |= PAYLOAD_TYPE_G726_40;
            }

            else if (_audioFormat == AUDIOFORMAT_G72632)
            {
                head->headPT |= PAYLOAD_TYPE_G726_32;
            }
            else if (_audioFormat == AUDIOFORMAT_G72624)
            {
                head->headPT |= PAYLOAD_TYPE_G726_24;
            }
            else if (_audioFormat == AUDIOFORMAT_G72616)
            {
                head->headPT |= PAYLOAD_TYPE_G726_16;
            }
            else
            {
                head->headPT |= PAYLOAD_TYPE_G726;
            }
        }
        // 测试保存文件
        // LOG_DUBG
        if (_isTalk && _isSaveTalk)
        {
            std::stringstream outfileName;
            outfileName << AppSetting::Instance()->holdTalkWebPath<<_url<<".terminal.audio";
            createdirectories(outfileName.str());
            std::ofstream outfile;
            outfile.open(outfileName.str(), std::ios::app);
            if (!outfile)
            {
                std::stringstream ss;
                ss <<"Failed to open audio file:"<<outfileName.str();
                loge(ss.str());
            }
            else
            {
                Rtp808HeadBaseA* headA = reinterpret_cast<Rtp808HeadBaseA*>(const_cast<uint8_t*>(data));
                auto audioDataLen = swapBigEndian(headA->dataLen);
                outfile.write((char*)headA->data, audioDataLen);
                outfile.close();

                std::stringstream ss;
                ss <<"save audio ("<<audioDataLen<<"/"<<headA->dataLen<<"):"<< outfileName.str();
                logd(ss.str());
                PrintBuffer(data+4, 32);
            }
        }
        
        // 对讲录音时过滤音频
        if (_isRecordAudio==1)
        {
            int dt =  head -> dataType;
            if (dt != RTP_808_DATATYPE_A)
            {
                return -1;
            }
        }

        // 过滤i frame
        
        if (head->dataType!=RTP_808_DATATYPE_A && ( _waitIFrame || _firstFrame))
        {
            if (head->dataType != RTP_808_DATATYPE_I)
            {
                // logd("Skip frame:"+std::to_string(head->dataType));
                return -2;
            }
            else
            {
                logd("Find i frame");
                _waitIFrame = false;
                _firstFrame = false;
            }
        }

        return 0;
    }
    
    void MediaClientConnection::OnReadyWebSocket()
    {
        logd("wait message,url:"+_url);
    }
    bool MediaClientConnection::CheckTimeout(int timeoutMilli)
    {
        auto bret = BaseProtocol::CheckTimeout(timeoutMilli);
        if (bret)
        {
            this->sendMessage(EErrorCode::MediaDataTimeout);
        }
        return bret;
    }
    void MediaClientConnection::OnData(char* data, int dataLen)
    {
        BaseProtocol::OnData(data, dataLen);
        
        // logstream(_logReadFlag, dataLen, _readBytesAll, (_isTalk?STREAM_LOG_RATE:1));        
         

        _readParam.second += dataLen;
        // LOG_DEBUG << "dataLen:" << dataLen <<",status="<< _status<< LOG_ENDL;
        WEBSOCKET_STATUS lastStatus = _status;
        if(_status != WEBSOCKET_INIT)
        {
            // logd
            // new
            if (_roomKey.length()>0)
            {
                if (_onDataCallback)
                {
                    _onDataCallback(this,this, (char*)data, dataLen);
                }
            }
            
            if (parse(dataLen) == -1)
            {
                this->Close();
            }
        }
        else
        {
            int result = recvHandShakeData();

            if (result == -1)
            {
                loge("Error connect");
                _streamInfo.message = "Error connect";
                this->Close();
                return;
            }
            // if(_version != "13" || _key.size() == 0)
            // {
            //     loge("Error version");
            //     _streamInfo.message = "Error version";
            // }
            result = sendHandShakeData();
            if (result == -1)
            {
                loge("Error send");
                _streamInfo.message = "Error send";
                this->Close();
                return;
            }
        }

        // LOG_DEBUG << "_status:" << _status <<",lastStatus="<< lastStatus<< LOG_ENDL;
        if(_status == SEND_HANDSHAKE && lastStatus != _status)
        {
            return OnReadyWebSocket();
        }
    }

    void MediaClientConnection::OnAlloc(uv_buf_t *buf, int suggested)
    {
        // std::cout << "OnAlloc2:ptr0="<<static_cast<void *>(readParam.first.data()) << std::endl;
        
        int freeSize = _readParam.first.size() - _readParam.second;
        if(freeSize < READ_BUFFER_STEP)
        {
            int newSize = _readParam.first.size() + READ_BUFFER_STEP;
            if (newSize >  AppSetting::Instance()->readbufferMax)
            {
                std::stringstream ss;
                ss << "Read buffer full:"<<errno;
                loge(ss.str());
                _streamInfo.message = "Buffer full(r)!";
                this->Close();
                return;
            }
            _readParam.first.resize(newSize);
        }
        buf->base = (char*)_readParam.first.data() + _readParam.second;
        buf->len = _readParam.first.size() - _readParam.second;
    } 
    void MediaClientConnection::OnRecvData()
    {
        uv_buf_t buf={};
        OnAlloc(&buf, 0);
        if (buf.base && buf.len>0)
        {
            auto iret = read(this->getfd(), buf.base, buf.len);
            if (iret>0)
            {
                OnData(buf.base, iret);   
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
            }
            else
            {
                loge("error read client:"+std::to_string(iret)+",errno="+std::to_string(errno));
                this->Close();
            }
        }
        
    }

    void MediaClientConnection::generatePackageHead(int dataLen, char* head, int& headLen)
    {
        headLen = 0;
    }
    void MediaClientConnection::generatePackageTail(int dataLen, char* tail, int& tailLen)
    {
        tailLen = 0;
    }
    void MediaClientConnection::OnClose()
    {
        logd("");

        BaseProtocol::OnClose();

        if(_onRelease)
        {
            _onRelease(this,this);
            _onRelease = nullptr;
        }
    }

    void MediaClientConnection::OnConnection()
    {
        BaseProtocol::OnConnection();
    }
    void MediaClientConnection::OnReady()
    {
        BaseProtocol::OnReady();
    }

    void MediaClientConnection::onMessage(const std::string& str)
    {     
        auto result = -1;
        cJSON* cjson = nullptr;
        do
        {
            logd(str);
            cjson = cJSON_Parse(str.data());
            if (!cjson)
            {
                break;
            }
            cJSON* dataNode = cJSON_GetObjectItem(cjson, "data");
            if (!dataNode)
            {
                break;
            }
            cJSON* msgHeadNode = cJSON_GetObjectItem(dataNode, "msgHead");
            cJSON* msgBodyNode = cJSON_GetObjectItem(dataNode, "msgBody");
            if (!msgBodyNode||!msgHeadNode)
            {
                break;
            }
            cJSON* msgIDNode = cJSON_GetObjectItem(msgHeadNode, "msgID");
            if (!msgIDNode)
            {
                break;
            }
            result = 0;

            auto msgID = msgIDNode->valueint;
            switch (msgID)
            {
            case 50001:
                onMessagePlay(msgBodyNode);
                break;
            case 50002:
                onMessageControl(msgBodyNode);
                break;
            case 50003:
                onMessageRtcOffer(msgBodyNode);
                break;
            case 50004:
                onMessageRtcIceCandidate(msgBodyNode);
                break;
            default:
                result = -1;
                break;
            }
            /* code */
        } while (false);
        if (result == -1)
        {
            loge("fail parse json:"+str);
        }
        
        if (cjson)
        {
            cJSON_Delete(cjson);
        }

    }
    void MediaClientConnection::onMessagePlay(cJSON* pars)
    {
        int errCode = 0;
        if ((errCode = loadPlayerSetting(pars)) != 0)
        {
            // loge("Play parameter miss! " + std::to_string(errCode));
            this->sendMessage(errCode);
            this->Close();
            return;   
        }


        int simLength = 12;
        if (_playerSetting.deviceType == DEVICETYPE_YUEBIAO)
        {
            simLength = 20;
        }
        
        auto offsetNumber = simLength - _playerSetting.simcardNumber.size();
        if (offsetNumber>0)
        {
            std::string str(offsetNumber,'0');
            _playerSetting.simcardNumber = str + _playerSetting.simcardNumber;
        }

        _streamInfo.simNumber = _playerSetting.simcardNumber;
        _streamInfo.channel = _playerSetting.channelNumber;
        _streamInfo.vehicleId = _playerSetting.vehicleId;
        _uuid = _playerSetting.vehicleId;
        _audioFormat = _playerSetting.audioFormat;
        

        auto newurl = "/" + _streamInfo.simNumber + "/" + _streamInfo.channel;
        std::stringstream ss;
        ss <<"update url:"<< newurl << ",audioFormat="<<_audioFormat;
        logd(ss.str());
        _url = newurl;

        _roomKey = ZWRoom::addClient(std::static_pointer_cast<MediaClientConnection>(shared_from_this()));
        if (_roomKey.size()>0)
        {
            _streamInfo.uuid = _roomKey;
            _streamInfo.playType = _isPlayback?'1':_isTalk?'2':'0';
            _streamInfo.userID = _playerSetting.userID;
            this->sendMessage(0, "等待终端连接中");

            if (_playerSetting.disableData == "1")
            {
                this->sendMessage(EErrorCode::RoomKey, _roomKey);
                auto iter = MediaWebSocketService::Instance()->SharePlayerSettings.find(_roomKey);
                if (iter == MediaWebSocketService::Instance()->SharePlayerSettings.end())
                {
                    MediaWebSocketService::Instance()->SharePlayerSettings[_roomKey] = _playerSetting;
                }
                else
                {
                    MediaWebSocketService::Instance()->SharePlayerSettings.insert(std::pair<std::string, PlayerSetting>(_roomKey, _playerSetting));
                }
            }
        }
        else
        {
            this->Close();
        }
        OnReady();
    }
    void MediaClientConnection::onMessageControl(cJSON* pars)
    {
        int errCode = 0;
        ControlSetting controlSetting;
        if ((errCode = loadControlSetting(pars, controlSetting)) != 0)
        {
            logd(pars->string);
            // loge("Control parameter miss! " + std::to_string(errCode));
            this->sendMessage(errCode);
            this->Close();
            return;   
        }

        if (_onControlCallback)
        {
            // logd("changeStreamType="+controlSetting.streamType+",closeVideoType="+controlSetting.closeVideoType+",control"+controlSetting.control);
            _onControlCallback(this,this, controlSetting);
        }
    }
    void MediaClientConnection::onMessageRtcOffer(cJSON* pars){
        
    }
    void MediaClientConnection::onMessageRtcIceCandidate(cJSON* pars){
        
    }
    
    int MediaClientConnection::loadPlayerSetting(cJSON* pars)
    {
        // 
        cJSON* disableDataNode = cJSON_GetObjectItem(pars,"disableData");
        if (disableDataNode && disableDataNode->type == cJSON_String)
        {
            _playerSetting.disableData = disableDataNode->valuestring;
        }
        


        // 必要参数
        cJSON* vehicleIdNode = cJSON_GetObjectItem(pars,"vehicleId");
        cJSON* simcardNumberNode = cJSON_GetObjectItem(pars,"simcardNumber");
        cJSON* channelNumberNode = cJSON_GetObjectItem(pars,"channelNumber");
        cJSON* sampleRateNode = cJSON_GetObjectItem(pars,"sampleRate");
        cJSON* channelCountNode = cJSON_GetObjectItem(pars,"channelCount");
        cJSON* audioFormatNode = cJSON_GetObjectItem(pars,"audioFormat");
        cJSON* playTypeNode = cJSON_GetObjectItem(pars,"playType");
        cJSON* dataTypeNode = cJSON_GetObjectItem(pars,"dataType");
        cJSON* userIDNode = cJSON_GetObjectItem(pars,"userID");

        cJSON* deviceIDNode = cJSON_GetObjectItem(pars,"deviceID");
        cJSON* streamTypeNode = cJSON_GetObjectItem(pars,"streamType");
        cJSON* deviceTypeNode = cJSON_GetObjectItem(pars,"deviceType");
        if (!vehicleIdNode || !simcardNumberNode || !channelNumberNode || !sampleRateNode || !channelCountNode || !audioFormatNode || !playTypeNode || !dataTypeNode || !userIDNode || !deviceIDNode || !streamTypeNode)
        {
            return EErrorCode::ParameterMissBase;
        }
        if (vehicleIdNode->type != cJSON_String||simcardNumberNode->type != cJSON_String||channelNumberNode->type != cJSON_String||sampleRateNode->type != cJSON_String||channelCountNode->type != cJSON_String||audioFormatNode->type != cJSON_String||playTypeNode->type != cJSON_String||dataTypeNode->type != cJSON_String||userIDNode->type != cJSON_String||deviceIDNode->type != cJSON_String||streamTypeNode->type != cJSON_String)
        {
            return EErrorCode::ParameterMissBase;
        }
        
        _playerSetting.vehicleId = vehicleIdNode->valuestring;
        _playerSetting.simcardNumber = simcardNumberNode->valuestring;
        _playerSetting.channelNumber = channelNumberNode->valuestring;
        _playerSetting.sampleRate = sampleRateNode->valuestring;
        _playerSetting.channelCount = channelCountNode->valuestring;
        _playerSetting.audioFormat = audioFormatNode->valuestring;
        _playerSetting.playType = playTypeNode->valuestring;
        _playerSetting.dataType = dataTypeNode->valuestring;
        _playerSetting.userID = userIDNode->valuestring;
        _playerSetting.deviceID = deviceIDNode->valuestring;
        _playerSetting.streamType = streamTypeNode->valuestring;
        _playerSetting.deviceType = "1";

        if (deviceTypeNode && deviceTypeNode->type == cJSON_String)
        {
            _playerSetting.deviceType = deviceTypeNode->valuestring;
        }
        

        cJSON* rawPackageNode = cJSON_GetObjectItem(pars,"rawPackage");
        if (rawPackageNode)
        {
            _playerSetting.forward0Copy = rawPackageNode->valuestring;
        }
        if (!AppSetting::Instance()->ZeroCopyEnabled)
        {
            _playerSetting.forward0Copy = "0";
        }
        
        // 细分
        cJSON* monitorIdNode = cJSON_GetObjectItem(pars,"monitorId");
        cJSON* clientIdNode = cJSON_GetObjectItem(pars,"clientId");
        if (monitorIdNode && monitorIdNode->type==cJSON_String)
        {
            _playerSetting.monitorId = monitorIdNode->valuestring;
        }
        if (clientIdNode && clientIdNode->type==cJSON_String)
        {
            _playerSetting.clientId = clientIdNode->valuestring;
        }
        

        
        // 
        if (_isPlayback)//(_playerSetting.playType == "TRACK_BACK")
        {
            // ----------------------------------------------------------------回放时使用
            cJSON* remoteModeNode = cJSON_GetObjectItem(pars,"remoteMode");
            cJSON* startTimeNode = cJSON_GetObjectItem(pars,"startTime");
            cJSON* endTimeNode = cJSON_GetObjectItem(pars,"endTime");
            cJSON* forwardOrRewindNode = cJSON_GetObjectItem(pars,"forwardOrRewind");
            cJSON* storageTypeNode = cJSON_GetObjectItem(pars,"storageType");
            cJSON* fragmentsNode = cJSON_GetObjectItem(pars,"fragments");
            if (remoteModeNode)
            {
                if (!remoteModeNode||!startTimeNode||!forwardOrRewindNode||!storageTypeNode)
                {
                    return EErrorCode::ParameterMissPlayback;
                }
                if (remoteModeNode->type != cJSON_String||startTimeNode->type != cJSON_String||forwardOrRewindNode->type != cJSON_String||storageTypeNode->type != cJSON_String)
                {
                    return EErrorCode::ParameterMissPlayback;
                }
                // fragments | endtime 两个参数二选一
                if (!fragmentsNode && !endTimeNode)
                {
                    return EErrorCode::ParameterMissPlayback;
                }
                if ((fragmentsNode&&fragmentsNode->type != cJSON_Array)||(endTimeNode&&endTimeNode->type != cJSON_String))
                {
                    return EErrorCode::ParameterMissPlayback;
                }
                
                

                _playerSetting.remoteMode = remoteModeNode->valuestring;
                _playerSetting.startTime = startTimeNode->valuestring;
                _playerSetting.forwardOrRewind = forwardOrRewindNode->valuestring;
                _playerSetting.storageType = storageTypeNode->valuestring;
                if (endTimeNode)
                {
                    _playerSetting.endTime = endTimeNode->valuestring;
                }
                if (fragmentsNode)
                {
                    auto fragmentsCount = cJSON_GetArraySize(fragmentsNode);
                    for (auto i = 0; i < fragmentsCount; i++)
                    {
                        auto fragmentNode = cJSON_GetArrayItem(fragmentsNode, i);
                        auto fragmetnStartNode = cJSON_GetObjectItem(pars,"startTime");
                        auto fragmetnEndNode = cJSON_GetObjectItem(pars,"endTime");
                        if (!fragmetnStartNode||!fragmetnEndNode)
                        {
                            return EErrorCode::ParameterMissPlayback;
                        }
                        if (fragmetnStartNode->type != cJSON_String||fragmetnEndNode->type != cJSON_String)
                        {
                            return EErrorCode::ParameterMissPlayback;
                        }
                        PlayerFragment fragment;
                        fragment.startTime = fragmetnStartNode->valuestring;
                        fragment.endTime = fragmetnEndNode->valuestring;
                        fragment.start_point = str2time1078(fragmetnStartNode->valuestring);
                        fragment.end_point = str2time1078(fragmetnEndNode->valuestring);
                        _playerSetting.fragments.push_back(fragment);
                    }
                    _playerSetting.startTimePointAbs = str2time1078(_playerSetting.startTime);
                    _playerSetting.startTimePoint = std::chrono::system_clock::now();
                    
                }
            }
        }
        
        return 0;
    }
    
    /*
    {
    "data":{
        "msgHead":{
            "msgID":50000
        },
        "msgBody":{
            "value":1
        }
    }
    }
    */

    int MediaClientConnection::loadControlSetting(cJSON* pars, ControlSetting &controlSetting)
    {
        if (_isPlayback)//(_playerSetting.playType == "TRACK_BACK")
        {
            // 回放
            cJSON* remoteNode = cJSON_GetObjectItem(pars,"remote");
            cJSON* dragPlaybackTimeNode = cJSON_GetObjectItem(pars,"dragPlaybackTime");
            cJSON* forwardOrRewindNode = cJSON_GetObjectItem(pars,"forwardOrRewind");
            if (!remoteNode || !dragPlaybackTimeNode || !forwardOrRewindNode)
            {
                return EErrorCode::ParameterMissControl;
            }
            if (remoteNode->type != cJSON_String||dragPlaybackTimeNode->type != cJSON_String||forwardOrRewindNode->type != cJSON_String)
            {
                return EErrorCode::ParameterMissControl;
            }
            controlSetting.remote = remoteNode->valuestring;
            controlSetting.dragPlaybackTime = dragPlaybackTimeNode->valuestring;
            controlSetting.forwardOrRewind = forwardOrRewindNode->valuestring;
        }
        else
        {
            // 实时
            cJSON* controlNode = cJSON_GetObjectItem(pars,"control");
            cJSON* changeStreamTypeNode = cJSON_GetObjectItem(pars,"changeStreamType");
            cJSON* closeVideoTypeNode = cJSON_GetObjectItem(pars,"closeVideoType");
            if (!controlNode || !changeStreamTypeNode || !closeVideoTypeNode)
            {
                return EErrorCode::ParameterMissControl;
            }
            if (controlNode->type != cJSON_String||changeStreamTypeNode->type != cJSON_String||closeVideoTypeNode->type != cJSON_String)
            {
                return EErrorCode::ParameterMissControl;
            }
            controlSetting.control = controlNode->valuestring;
            controlSetting.streamType = changeStreamTypeNode->valuestring;
            controlSetting.closeVideoType = closeVideoTypeNode->valuestring;
        }
        return 0;
    }

    void MediaClientConnection::onRtpData(uint8_t* rtpData, int len)
    {
        logd("");
        Rtp808HeadBaseV* head = reinterpret_cast<Rtp808HeadBaseV*>(const_cast<uint8_t*>(rtpData));
        if (head->dataType == RTP_808_DATATYPE_T){
            logd("RTP_808_DATATYPE_T");
            Rtp808HeadBaseT* headT = reinterpret_cast<Rtp808HeadBaseT*>(const_cast<uint8_t*>(rtpData));
            auto dataLen = swapBigEndian(headT->dataLen);
            std::string strMessage(dataLen, 0);
            if (dataLen>=len-sizeof(Rtp808HeadBaseT))
            {
                memcpy(strMessage.data(), headT->data, dataLen);
                onMessage(strMessage);
            }
            else
            {
                this->sendMessage(ErrorMessageData);
                this->Close();
            }
            
        } else if (head->dataType == RTP_808_DATATYPE_A){
            if (_onAudioDataCallback)
            {
                _onAudioDataCallback(this, this, (char*)rtpData, len);
            }
        }
    }

    void MediaClientConnection::sendMessage(int code, const std::string& message)
    {
        if (code>=0)
        {
            logd("code:"+std::to_string(code)+", message:"+message);
        }
        else
        {
            loge("code:"+std::to_string(code)+", message:"+message);
        }
        
        
        std::stringstream ss;
        ss<<"{\"data\":{\"msgHead\":{\"msgID\":50101},\"msgBody\":{\"code\":"<< code <<",\"msg\":\""<< message <<"\"}}}";
        this->sendMessage(ss.str().c_str(), ss.str().length());
    }
}