#include "VoipMsSMSClient.h"
#include <QTextStream>
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDateTime>
#include <QStringList>
#include "MasterCtrl.h"
#include <QDebug>

CVoipMsSMSClient::CVoipMsSMSClient()
{
    mVOIPMSSocket = new QNetworkAccessManager();
    connect(mVOIPMSSocket,SIGNAL(finished(QNetworkReply*)),this,SLOT(VoipServerReplyFinished(QNetworkReply*)));
    connect(mVOIPMSSocket,SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),this,SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));

    mVOIPMsNotificationServer = new QTcpServer;
    connect(mVOIPMsNotificationServer,SIGNAL(newConnection()),this,SLOT(VoipNotificationServerConnected()));
   // mVOIPMsNotificationServer->listen(QHostAddress::Any,80);

    mCheckNewSMSTimer = new QTimer();
    connect(mCheckNewSMSTimer,SIGNAL(timeout()),this,SLOT(CheckNewSMSTimerExpired()));
    mCheckNewSMSTimer->setSingleShot(false);

    //mFirstDownloadDone = false;

    mProgramHandle = 0;

    mSMSDownloadState = VOIPMS_SMS_DOWNLOAD_INIT_STATE;

}

CVoipMsSMSClient::~CVoipMsSMSClient()
{
    delete mVOIPMSSocket;
    mSMSMessagesList.clear();
    mVOIPMsNotificationServer->close();
    delete mVOIPMsNotificationServer;
    mCheckNewSMSTimer->stop();
    delete mCheckNewSMSTimer;
}

unsigned int CVoipMsSMSClient::SetVOIPMsSettings(CVoipMSSMSSettings *SettingsData)
{
    mVOIPMsSettings = SettingsData;

    return RET_OK;
}

int CVoipMsSMSClient::DownloadSMSFromServer()
{

    qDebug("Downloading messages until %s",mVOIPMsSettings.mStartDate.toString("yyyy-MM-dd").toUtf8().data());
    mCurStartDate = QDate::currentDate().addDays(-VOIP_MS_SMS_DATESPAN);
    mSMSDownloadState = VOIPMS_SMS_DOWNLOAD_SPAN_MSGS_STATE;
    SendSMSDownloadRequest(mCurStartDate,QDate::currentDate());
    mSMSMessagesList.clear();

    return RET_OK;
}

int CVoipMsSMSClient::SendSMSDownloadRequest(QDate StartDate, QDate EndDate)
{
    QString Url;
    Url.clear();
    QTextStream UrlStream(&Url);

 //   qDebug() << "Sending request for dates from: " << StartDate.toString("yyyy-MM-dd") << " to: " << EndDate.toString("yyyy-MM-dd");

//       Url = "https://www.voip.ms/api/v1/rest.php?api_username=jean-francois@jfmartel.ca&api_password=Pentium2&method=getSMS&from=2015-11-01&to=2015-11-11&did=5143606463&limit=50";

    StopSMSCheckTimer();

    UrlStream << VOIP_MS_API_URL
              << "api_username=" << mVOIPMsSettings.mUsername << "&"
              << "api_password=" << mVOIPMsSettings.mPassword << "&"
              << "method=" << "getSMS" << "&"
              << "from=" << StartDate.toString("yyyy-MM-dd") << "&"
              << "to=" << EndDate.toString("yyyy-MM-dd") << "&"
              << "did=" << mVOIPMsSettings.mDefaultDID << "&"
              << "limit=" << VOIP_MS_SMS_MAX_COUNT;

    //qDebug() << "Cmd: " << Url;

    mVOIPMSSocket->get(QNetworkRequest(Url));
    mCurStartDate = EndDate;

    mLastRequestCmd = "getSMS";


    return RET_OK;
}

int CVoipMsSMSClient::SendSMS(QList<CSMSMessage> *SMSList)
{

    if(SMSList->size() == 0)
    {
        return RET_ERROR;
    }

    SendSMS(SMSList->at(0));

    if(SMSList->size() > 1)
    {
        for(int i = 1; i < SMSList->size(); i++)
        {
            mPendingSMSSendList.append(SMSList->at(i));
        }
    }

    return RET_OK;
}

int CVoipMsSMSClient::SendSMS(CSMSMessage Message)
{
    QString Url;
    Url.clear();
    QTextStream UrlStream(&Url);

    StopSMSCheckTimer();
    UrlStream << VOIP_MS_API_URL
              << "api_username=" << mVOIPMsSettings.mUsername << "&"
              << "api_password=" << mVOIPMsSettings.mPassword << "&"
              << "method=" << "sendSMS" << "&"
              << "did=" << Message.mDID << "&"
              << "dst=" << Message.mContact << "&"
              << "message=" << Message.mMessageText;

    qDebug() << "Sending SMS Msg : " << Url;
    mVOIPMSSocket->get(QNetworkRequest(Url));
    mLastRequestCmd = "sendSMS";

    return RET_OK;
}

int CVoipMsSMSClient::DownloadNewSMS()
{
   // SendSMSDownloadRequest(QDate::currentDate(),QDate::currentDate());
    return RET_OK;
}

int CVoipMsSMSClient::CheckForNewSMS()
{
   // qDebug("Check new SMS");
   // qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss") << ":" << "Check New SMS";
    if(mSMSMessagesList.isEmpty() == true)
    {
        return RET_ERROR;
    }


    QDate Today = QDate::currentDate();
    QDate StartDate = mSMSMessagesList.at(0).mDateTime.date();
    SendSMSDownloadRequest(StartDate,Today);
    return RET_OK;
}

unsigned int CVoipMsSMSClient::GetDidFromUserAccount(const QString username, const QString Password)
{
    QString Method = "getDIDsInfo";
    QString Url;
    Url.clear();
    QTextStream UrlStream(&Url);

    StopSMSCheckTimer();

    UrlStream << VOIP_MS_API_URL
              << "api_username=" << username << "&"
              << "api_password=" << Password << "&"
              << "method=" << Method << "&";

     mVOIPMSSocket->get(QNetworkRequest(Url));
     mLastRequestCmd = Method;

    return RET_OK;
}

void CVoipMsSMSClient::sslErrors(QNetworkReply *reply, QList<QSslError> errors)
{
    qDebug("Ssl errors...");
    reply->ignoreSslErrors();
}

void CVoipMsSMSClient::VoipServerReplyFinished(QNetworkReply *NetworkReply)
{
    if(NetworkReply->isFinished() == false)
        return;

    if(NetworkReply->error() != QNetworkReply::NoError)
    {
      //  qDebug("Network error... %d", NetworkReply->error());
        return;
    }

    QByteArray Reply = NetworkReply->readAll();
    NetworkReply->deleteLater();

    QJsonDocument JsonReply = QJsonDocument::fromJson(Reply);
    QJsonObject JsonObject = JsonReply.object();
    QStringList Keys = JsonObject.keys();
    if(JsonObject["status"].toString() == "success")
    {
        if(mLastRequestCmd == "getSMS")
       // if(Keys.contains("sms"))
        {
            QJsonArray SMSArray = JsonObject["sms"].toArray();
            SMSReceived(&SMSArray);
        }
        else if(mLastRequestCmd == "getDIDsInfo")
       // else if(Keys.contains("dids"))
        {
            QJsonArray DIDsInfoArray = JsonObject["dids"].toArray();
            DIDsInfoReceived(&DIDsInfoArray);
        }
        else if(mLastRequestCmd == "sendSMS")
        {
            SendSMSAckReceived(true);
        }
    }
    else
    {
        qDebug() << "VOIP.MS reply: " << JsonObject["status"].toString();
        if(JsonObject["status"].toString() == "no_sms")
        {
            SMSReceived(0);
        }
        if(mLastRequestCmd == "sendSMS")
        {
            SendSMSAckReceived(false);
        }
        else
        {
            //Restart timer...
            StartSMSCheckTimer();
        }
    }
    Reply.clear();
}

int CVoipMsSMSClient::SendSMSAckReceived(bool Success)
{
    if(Success)
    {
        qDebug("SMS sent successfuly");
        if(mPendingSMSSendList.size() != 0)
        {
            CSMSMessage Msg = mPendingSMSSendList.takeFirst();
            SendSMS(Msg);
        }
        else
        {
            CheckForNewSMS();
//            StartSMSCheckTimer();
        }
    }
    else
    {
        qDebug("SMS send failed");
        mPendingSMSSendList.clear();
        StartSMSCheckTimer();
    }



    return RET_OK;
}

unsigned int CVoipMsSMSClient::SMSReceived(QJsonArray *SMSArray)
{

    QList<CSMSMessage> NewMessages;
    int NBMsgReceived;

    if(SMSArray != 0)
    {
        foreach (const QJsonValue & value, *SMSArray)
        {
            CSMSMessage NewMessage;
            QJsonObject obj = value.toObject();
            NewMessage.mContact = obj["contact"].toString();
            NewMessage.mDateTime = QDateTime::fromString(obj["date"].toString(),"yyyy-MM-dd HH:mm:ss");
            NewMessage.mDID = obj["did"].toString();
            NewMessage.mMessageText = obj["message"].toString();
            NewMessage.mType = (SmsType_t)obj["type"].toString().toInt();
            NewMessage.mVOIPMSDatabaseID = obj["id"].toString();//.toLongLong();
            NewMessages.append(NewMessage);
            //qDebug() << obj["date"].toString() << " : " << obj["id"].toString();
        }

        NBMsgReceived = NewMessages.size();
    //    qDebug() << "Received " << NBMsgReceived << "messages";


        if(mSMSMessagesList.size() >0 && NewMessages.size() > 0)
        {
            //remove existing messages...
            bool finished = false;

            QDateTime NewDate = NewMessages.at(0).mDateTime;
            QDateTime OldDate = mSMSMessagesList.at(0).mDateTime;

            if(NewDate >= OldDate)
            {
                while(!finished)
                {
                    //compare starting from the end for efficiency...
                    NewDate = NewMessages.last().mDateTime;
                    OldDate = mSMSMessagesList.at(0).mDateTime;

                    if(NewDate <= OldDate)
                    {
                        NewMessages.removeLast();
                        if(NewMessages.size() == 0)
                        {
                            finished = true;
                        }
                    }
                    else
                    {
                        finished = true;
                    }
                }
//                if(mFirstDownloadDone == true && NewMessages.size() > 0)
//                {
//                    mProgramHandle->NewSMSMessagesArrived(NewMessages);

//                    qDebug() << "Added " << NewMessages.size() << " new SMS messages";
//                    qDebug("-----------------------------------------------------------------------");
//                    qDebug(" ");
//                    for(int i = 0; i < NewMessages.size(); i++)
//                    {
//                        qDebug() << NewMessages.at(i).mDateTime.toString("yyyy-MM-dd hh:mm:ss") << " : " << NewMessages.at(i).mContact  << " : " << NewMessages.at(i).mMessageText.toUtf8().data();
//                    }
//                    qDebug("-----------------------------------------------------------------------");
//                    qDebug(" ");
//                }

//                NewMessages.append(mSMSMessagesList);
//                mSMSMessagesList = NewMessages;
//                StartSMSCheckTimer();

            }
            else
            {

                while(!finished)
                {
                    //compare starting from the end for efficiency...
                    NewDate = NewMessages.at(0).mDateTime;
                    OldDate = mSMSMessagesList.last().mDateTime;

                    if(NewDate >= OldDate)
                    {
                        NewMessages.removeAt(0);
                        if(NewMessages.size() == 0)
                        {
                            finished = true;
                        }
                    }
                    else
                    {
                        finished = true;
                    }
                }
//                 mSMSMessagesList.append(NewMessages);
//                 StartSMSCheckTimer();
//                 if(mFirstDownloadDone == true && NewMessages.size() > 0)
//                 {
//                     mProgramHandle->NewSMSMessagesArrived(NewMessages);

//                     qDebug() << "Added " << NewMessages.size() << " new SMS messages";
//                     qDebug("-----------------------------------------------------------------------");
//                     qDebug(" ");
//                     for(int i = 0; i < NewMessages.size(); i++)
//                     {
//                         qDebug() << NewMessages.at(i).mDateTime.toString("yyyy-MM-dd hh:mm:ss") << " : " << NewMessages.at(i).mContact  << " : " << NewMessages.at(i).mMessageText.toUtf8().data();
//                     }
//                     qDebug("-----------------------------------------------------------------------");
//                     qDebug(" ");
//                 }
            }
        }
//        else
//        {
//            mSMSMessagesList.append(NewMessages);
//            StartSMSCheckTimer();
//        }
    }
    else
    {
        NewMessages.empty();
        NBMsgReceived = 0;
    }


//    if(NewMessages.size() != 0)
//    {
//        mSMSMessagesList.append(NewMessages);
//        qDebug("Added %d new msgs.  mCurStartDate:%s", NewMessages.size(),mCurStartDate.toString("yyyy-MM-dd").toUtf8().data());
//    }

    switch(mSMSDownloadState)
    {
        case VOIPMS_SMS_DOWNLOAD_INIT_STATE:
        {
            qDebug("Error, mSMSDownloadState = INIT_STATE in SMSReceived()");
            break;
        }
        case VOIPMS_SMS_DOWNLOAD_SPAN_MSGS_STATE:
        {
            if(NewMessages.size() != 0)
            {
                mSMSMessagesList.append(NewMessages);
//                qDebug("Added %d new msgs.  mCurStartDate:%s", NewMessages.size(),mCurStartDate.toString("yyyy-MM-dd").toUtf8().data());
            }
            //Restart at the last day received...
            mCurStartDate = mSMSMessagesList.last().mDateTime.date();
            QDate EarlierDate = mCurStartDate.addDays(-VOIP_MS_SMS_DATESPAN);
            if(EarlierDate < mVOIPMsSettings.mStartDate )
            {
                //Clipping span.
//                qDebug("Clipping span...");
                EarlierDate = mVOIPMsSettings.mStartDate;

//                qDebug("Requesting data for last block of span");
                mSMSDownloadState = VOIPMS_SMS_DOWNLOAD_LAST_BLOCK_MSGS_STATE;
            }
//            qDebug("Continue receiving from %s to %s ...",mCurStartDate.toString("yyyy-MM-dd").toUtf8().data(),EarlierDate.toString("yyyy-MM-dd").toUtf8().data());
            SendSMSDownloadRequest(EarlierDate,mCurStartDate);
            break;
        }
        case VOIPMS_SMS_DOWNLOAD_LAST_BLOCK_MSGS_STATE:
        {
            if(NewMessages.size() != 0)
            {
                mSMSMessagesList.append(NewMessages);
//                qDebug("Added %d new msgs.  mCurStartDate:%s", NewMessages.size(),mCurStartDate.toString("yyyy-MM-dd").toUtf8().data());
            }

            if(NBMsgReceived == VOIP_MS_SMS_MAX_COUNT)
            {
                mCurStartDate = mSMSMessagesList.last().mDateTime.date();
//                qDebug("Continue receiving from %s to %s ...",mVOIPMsSettings.mStartDate.toString("yyyy-MM-dd").toUtf8().data(),mVOIPMsSettings.mStartDate.toString("yyyy-MM-dd").toUtf8().data());
                SendSMSDownloadRequest(mCurStartDate,mVOIPMsSettings.mStartDate);//download for the first day of the span only...
            }
            else
            {
                qDebug() << "Finished download of " << mSMSMessagesList.size() << " SMS messages";
//                qDebug("-----------------------------------------------------------------------");
//                qDebug(" ");
//                for(int i = 0; i < mSMSMessagesList.size(); i++)
//                {
//                    qDebug() << mSMSMessagesList.at(i).mDateTime.toString("yyyy-MM-dd hh:mm:ss") << " : " << mSMSMessagesList.at(i).mContact  << " : " << mSMSMessagesList.at(i).mMessageText.toUtf8().data();
//                }
//                qDebug("-----------------------------------------------------------------------");
//                qDebug(" ");


                mSMSDownloadState = VOIPMS_SMS_GET_NEW_MSGS_STATE;
                StartSMSCheckTimer();
     //           qDebug("Timer started in VOIPMS_SMS_DOWNLOAD_LAST_DAY_MSGS_STATE");
            }
            break;
        }
        case VOIPMS_SMS_GET_NEW_MSGS_STATE:
        {

            if(NewMessages.size() != 0)
            {
                for(int i = NewMessages.size(); i > 0; i--)
                {
                    mSMSMessagesList.prepend(NewMessages[i-1]);
                }
//                qDebug("Added %d new msgs.  mCurStartDate:%s", NewMessages.size(),mCurStartDate.toString("yyyy-MM-dd").toUtf8().data());
            }

            StartSMSCheckTimer();
//            qDebug("Timer started in VOIPMS_SMS_GET_NEW_MSGS_STATE");

            if(NewMessages.size() > 0)
            {
                mProgramHandle->NewSMSMessagesArrived(NewMessages);

                qDebug() << "Added " << NewMessages.size() << " new SMS messages";
                qDebug("-----------------------------------------------------------------------");
                qDebug(" ");
                for(int i = 0; i < NewMessages.size(); i++)
                {
                    qDebug() << NewMessages.at(i).mDateTime.toString("yyyy-MM-dd hh:mm:ss") << " : " << NewMessages.at(i).mContact  << " : " << NewMessages.at(i).mMessageText.toUtf8().data();
                }
                qDebug("-----------------------------------------------------------------------");
                qDebug(" ");
                break;
            }
        }
    }



//        mCurStartDate = mSMSMessagesList.last().mDateTime.date();
//        static bool DateClipped = false;;
//        //if(NBMsgReceived == VOIP_MS_SMS_MAX_COUNT)
//        qDebug("Received %d msgs.  mCurStartDate:%s", NBMsgReceived,mCurStartDate.toString("yyyy-MM-dd").toUtf8().data());
//        if(mCurStartDate > mVOIPMsSettings.mStartDate && DateClipped == false)
//        {
//            //Restart at the last day received...
//            mCurStartDate = mSMSMessagesList.last().mDateTime.date();
//            QDate EarlierDate = mCurStartDate.addDays(-VOIP_MS_SMS_DATESPAN);
//            if(EarlierDate < mVOIPMsSettings.mStartDate )
//            {
//                //Clipping span.
//                qDebug("Clipping span...");
//                EarlierDate = mVOIPMsSettings.mStartDate;
//                DateClipped = true;
//            }
//            qDebug("Continue receiving from %s to %s ...",mCurStartDate.toString("yyyy-MM-dd").toUtf8().data(),EarlierDate.toString("yyyy-MM-dd").toUtf8().data());
//            SendSMSDownloadRequest(EarlierDate,mCurStartDate);
//        }
//        else if (/*(mCurStartDate == mVOIPMsSettings.mStartDate) &&*/ (NBMsgReceived == VOIP_MS_SMS_MAX_COUNT))
//        {
//            //We have covered the entire time span but we didn't get all of the messages...
//            SendSMSDownloadRequest(mCurStartDate,mCurStartDate);//download for the first day of the span only...
//        }
//        else
//        {

//            if(mFirstDownloadDone == false)
//            {
//                qDebug() << "Finished download of " << mSMSMessagesList.size() << " SMS messages";
//                qDebug("-----------------------------------------------------------------------");
//                qDebug(" ");
//                for(int i = 0; i < mSMSMessagesList.size(); i++)
//                {
//                    qDebug() << mSMSMessagesList.at(i).mDateTime.toString("yyyy-MM-dd hh:mm:ss") << " : " << mSMSMessagesList.at(i).mContact  << " : " << mSMSMessagesList.at(i).mMessageText.toUtf8().data();
//                }
//                qDebug("-----------------------------------------------------------------------");
//                qDebug(" ");


//                mFirstDownloadDone = true;
//                DateClipped = false;
////                mCheckNewSMSTimer->start(VOIP_MS_SMS_CHECK_TIMEOUT);
//                StartSMSCheckTimer();
//                qDebug("Timer started");
//            }

//        }
//    }
//    else
//    {
//        qDebug("No SMS to download in this period.");
//        StartSMSCheckTimer();
//    }

    return RET_OK;
}

unsigned int CVoipMsSMSClient::NewSMSNotification(QString DID)
{
    if(DID != mVOIPMsSettings.mDefaultDID)
    {
        return RET_ERROR;
    }

    DownloadNewSMS();
    return RET_OK;
}

unsigned int CVoipMsSMSClient::DIDsInfoReceived(QJsonArray *DIDsInfoPtr)
{
    QStringList DIDs;
    QJsonArray DIDsInfo = *DIDsInfoPtr;

    foreach (const QJsonValue & value, DIDsInfo)
    {
        QJsonObject DIDInfo = value.toObject();
        QString CurDID = DIDInfo["did"].toString();
        int SMSEnabled = DIDInfo["sms_enabled"].toString().toInt();
        if(SMSEnabled == 1)
        {
            DIDs.append(CurDID);
        }
        qDebug("DID: %s - SMSEnabled %d",CurDID.toUtf8().data(),SMSEnabled);

        emit DIDSFetched(DIDs);
    }

    StartSMSCheckTimer();

    return RET_OK;
}

void CVoipMsSMSClient::VoipNotificationServerConnected()
{
    qDebug("Client Connected");

    mClientConnection = mVOIPMsNotificationServer->nextPendingConnection();
    connect(mClientConnection,SIGNAL(readyRead()),this,SLOT(VoipNotificationServerDataAvail()));
   // ClientConnection->waitForReadyRead();

}

void CVoipMsSMSClient::VoipNotificationServerDataAvail()
{
    QString Notification(mClientConnection->readAll());
    QStringList Parts = Notification.split(" ");
    QString Data;
    QString Did;

    for(int i = 0; i < Parts.size(); i++)
    {
        if(Parts.at(i).contains("/?"))
        {
            Data = Parts.at(i);
            break;
        }
    }

    if(Data.isEmpty() == false)
    {
        Parts = Data.remove("/?").split("&");

        for(int i = 0; i < Parts.size(); i++)
        {
            if(Parts.at(i).contains("did="))
            {
                Data = Parts.at(i);
                Did = Data.remove("did=");
            }
        }
    }

    qDebug() << "New SMS from did: " << Did;

//    qDebug() << Notification;
    mClientConnection->close();

    NewSMSNotification(Did);
}

void CVoipMsSMSClient::CheckNewSMSTimerExpired()
{
    CheckForNewSMS();
}

QList<CSMSMessage> *CVoipMsSMSClient::GetSMSList()
{
    return &mSMSMessagesList;
}

int CVoipMsSMSClient::GetSMSCount()
{
    return mSMSMessagesList.size();
}

QString CVoipMsSMSClient::GetDefaultDID()
{
    return mVOIPMsSettings.mDefaultDID;
}

void CVoipMsSMSClient::StartSMSCheckTimer()
{
    if(mSMSDownloadState == VOIPMS_SMS_GET_NEW_MSGS_STATE)
    {
        mCheckNewSMSTimer->start(VOIP_MS_SMS_CHECK_TIMEOUT);
    }
    else
    {
        qDebug("Trying to start SMS timer outside VOIPMS_SMS_GET_NEW_MSGS_STATE");
    }
}

void CVoipMsSMSClient::StopSMSCheckTimer()
{
    mCheckNewSMSTimer->stop();
}

//https://www.voip.ms/api/v1/rest.php?api_username=jean-francois.martel@polymtl.ca&api_password=Pentium2&method=getBalance&advanced=True


//https://www.voip.ms/api/v1/rest.php?api_username=jean-francois.martel@polymtl.ca&api_password=Pentium2&method=getSMS&from=2014-01-01&to=2015-11-11&did=5143606463&limit=50

