#pragma once

#include "Common/json/json.hpp"
#include "Common/FSecure/WinHttp/WebProxy.h"
#include "Common/FSecure/WinHttp/Constants.h"

using json = nlohmann::json; //for easy parsing of json API: https://github.com/nlohmann/json

namespace FSecure
{
	class Discord
	{
	public:

		/// Constructor for the Discord Api class.
		/// @param userAgent - user agent to apply to all requests
		/// @param token - the bot token generated by Discord when an "app" was installed
		/// @param channelName - the name of the channel to create for all messages
		/// @param guildId - the id of the server/guild
		Discord(std::string const& userAgent, std::string const& token, std::string const& channelName, std::string const& guildId);

		/// Default constructor.
		Discord() = default;

		/// Write a message to the channel this Discord object is set to.
		/// @param text - the text of the message
		/// @return - the id of the message that was written to the channel.
		std::string WriteMessage(std::string const& text);

		/// Set the channel that this object uses for communications
		/// @param channelId - the channelId (not name) for all message comms.
		void SetChannel(std::string const& channelId);

		/// set the token for this object.
		/// @param token - the textual bot api token.
		void SetToken(std::string const& token);

		/// Creates a channel on Discord, if the channel exists already, will call ListChannels internally first to get the channelId.
		/// @param channelName - the actual name of the channel, such as "general".
		/// @return - the channelId of the new or already existing channel.
		std::string CreateChannel(std::string const& channelName);

		/// List all the channels in the server the object's bot token is tied to.
		/// @return - a map of {channelName -> channelId}
		std::map<std::string, std::string> ListChannels();

		/// Get all messages in the channel.
		/// @return - json of all messages
		json GetAllMessages();

		/// Edit a previously sent message.
		/// @param message - the message to update to, this will overwrite the previous message.
		/// @param messageId - the id of the message to update.
		void UpdateMessage(std::string const& message, std::string const& messageId);

		/// Create a thread on a message by writing a reply to it.
		/// @param text - the text to send as a reply.
		/// @param messageId - the id of the message that the reply is for.
		void WriteReply(std::string const& text, std::string const& messageId);

		/// Use Discord's file API to upload data as files. This is useful when a payload is large (for example during implant staging).
		/// This function is called internally whenever a WriteReply is called with a payload of more than 6k characters.
		/// @param data - the data to be sent.
		/// @param messageId - the message id, needed as this method is only used during WriteReply.
		void UploadFile(ByteView data, std::string const& messageId);

		/// Use Discord's File API to retrieve files.
		/// @param url - the url where the file can be retrieved.
		/// @return - the data within the file.
		std::string GetFile(std::string const& url);

		/// Delete a message from the channel
		/// @param timestamp - the timestamp of the message to delete.
		void DeleteMessage(std::string const& messageId);

		/// Delete entire channel
		void DeleteChannel();

		/// Delete array of messages in one go - reducing number of API calls needed
		void DeleteMessages(std::vector<std::string> const& replyIds);

		/// Delete messages in channel (helpful for purging orphaned messages and increasing channel performance)
		void DeleteAllMessages();

	private:

		/// The channel through which messages are sent and received, will be sent when the object is created.
		std::string m_channelId;

		/// The Discord Bot API token that allows the object access to the workspace. Needs to be manually created as described in documentation.
		std::string m_Token;

		/// The Discord Guild or Server the bot has been added to.
		std::string m_guildId;

		/// The user agent header
		std::string m_UserAgent;

		/// Hold proxy settings
		WinHttp::WebProxy m_ProxyConfig;

		/// Send http request, uses preset token for authentication
		ByteVector SendHttpRequest(std::string const& host, std::wstring const& contentType, std::vector<uint8_t> const& data, WinHttp::Method method);
		ByteVector SendHttpRequest(std::string const& host, WinHttp::ContentType contentType, std::vector<uint8_t> const& data, WinHttp::Method method);

		/// Send http request with json data, uses preset token for authentication
		json SendJsonRequest(std::string const& url, json const& data, FSecure::WinHttp::Method method);

		/// Send http GET request, uses preset token for authentication, expect response of application/json type
		json GetJsonResponse(std::string const& url);

		

	};

}

