/*
 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program. If not, see .
 */
#ifndef TRINITYCORE_SESSION_H
#define TRINITYCORE_SESSION_H
#include "AsyncCallbackProcessor.h"
#include "ClientBuildInfo.h"
#include "Duration.h"
#include "QueryResult.h"
#include "Realm.h"
#include "Socket.h"
#include "SslStream.h"
#include 
#include 
#include 
namespace pb = google::protobuf;
class ServiceBase;
namespace bgs::protocol
{
class Variant;
namespace account::v1
{
    class GetAccountStateRequest;
    class GetAccountStateResponse;
    class GetGameAccountStateRequest;
    class GetGameAccountStateResponse;
}
namespace authentication::v1
{
    class GenerateWebCredentialsRequest;
    class LogonRequest;
    class VerifyWebCredentialsRequest;
}
namespace game_utilities::v1
{
    class ClientRequest;
    class ClientResponse;
    class GetAllValuesForAttributeRequest;
    class GetAllValuesForAttributeResponse;
}
}
using namespace bgs::protocol;
namespace Battlenet
{
    class Session final : public Trinity::Net::Socket>
    {
        using BaseSocket = Socket>;
    public:
        struct LastPlayedCharacterInfo
        {
            Battlenet::RealmHandle RealmId;
            std::string CharacterName;
            uint64 CharacterGUID;
            uint32 LastPlayedTime;
        };
        struct GameAccountInfo
        {
            void LoadResult(Field const* fields);
            uint32 Id;
            std::string Name;
            std::string DisplayName;
            uint32 UnbanDate;
            bool IsBanned;
            bool IsPermanenetlyBanned;
            AccountTypes SecurityLevel;
            std::unordered_map CharacterCounts;
            std::unordered_map LastPlayedCharacters;
        };
        struct AccountInfo
        {
            void LoadResult(PreparedQueryResult result);
            uint32 Id;
            std::string Login;
            bool IsLockedToIP;
            std::string LockCountry;
            std::string LastIP;
            uint32 LoginTicketExpiry;
            bool IsBanned;
            bool IsPermanenetlyBanned;
            std::unordered_map GameAccounts;
        };
        explicit Session(Trinity::Net::IoContextTcpSocket&& socket);
        ~Session();
        void Start() override;
        bool Update() override;
        uint32 GetAccountId() const { return _accountInfo->Id; }
        uint32 GetGameAccountId() const { return _gameAccountInfo->Id; }
        void SendResponse(uint32 token, pb::Message const* response);
        void SendResponse(uint32 token, uint32 status);
        void SendRequest(uint32 serviceHash, uint32 methodId, pb::Message const* request, std::function callback)
        {
            _responseCallbacks[_requestToken] = std::move(callback);
            SendRequest(serviceHash, methodId, request);
        }
        void SendRequest(uint32 serviceHash, uint32 methodId, pb::Message const* request);
        void QueueQuery(QueryCallback&& queryCallback);
        uint32 HandleLogon(authentication::v1::LogonRequest const* logonRequest, std::function& continuation);
        uint32 HandleVerifyWebCredentials(authentication::v1::VerifyWebCredentialsRequest const* verifyWebCredentialsRequest, std::function& continuation);
        uint32 HandleGenerateWebCredentials(authentication::v1::GenerateWebCredentialsRequest const* request, std::function& continuation);
        uint32 HandleGetAccountState(account::v1::GetAccountStateRequest const* request, account::v1::GetAccountStateResponse* response);
        uint32 HandleGetGameAccountState(account::v1::GetGameAccountStateRequest const* request, account::v1::GetGameAccountStateResponse* response);
        uint32 HandleProcessClientRequest(game_utilities::v1::ClientRequest const* request, game_utilities::v1::ClientResponse* response);
        uint32 HandleGetAllValuesForAttribute(game_utilities::v1::GetAllValuesForAttributeRequest const* request, game_utilities::v1::GetAllValuesForAttributeResponse* response);
        std::string GetClientInfo() const;
        Trinity::Net::SocketReadCallbackResult ReadHandler() override;
    protected:
        bool ReadHeaderLengthHandler();
        bool ReadHeaderHandler();
        bool ReadDataHandler();
    private:
        void AsyncWrite(MessageBuffer* packet);
        uint32 VerifyWebCredentials(std::string const& webCredentials, std::function& continuation);
        typedef uint32(Session::*ClientRequestHandler)(std::unordered_map const&, game_utilities::v1::ClientResponse*);
        static std::unordered_map const ClientRequestHandlers;
        uint32 GetRealmListTicket(std::unordered_map const& params, game_utilities::v1::ClientResponse* response);
        uint32 GetLastCharPlayed(std::unordered_map const& params, game_utilities::v1::ClientResponse* response);
        uint32 GetRealmList(std::unordered_map const& params, game_utilities::v1::ClientResponse* response);
        uint32 JoinRealm(std::unordered_map const& params, game_utilities::v1::ClientResponse* response);
        MessageBuffer _headerLengthBuffer;
        MessageBuffer _headerBuffer;
        MessageBuffer _packetBuffer;
        std::shared_ptr _accountInfo;
        GameAccountInfo* _gameAccountInfo;          // Points at selected game account (inside _gameAccounts)
        std::string _locale;
        std::string _os;
        uint32 _build;
        ClientBuild::VariantId _clientInfo;
        Minutes _timezoneOffset;
        std::string _ipCountry;
        std::array _clientSecret;
        bool _authed;
        QueryCallbackProcessor _queryProcessor;
        std::unordered_map> _responseCallbacks;
        uint32 _requestToken;
    };
}
#endif // TRINITYCORE_SESSION_H