// Discord Rich Presence - plugin made by Mathew Simon.

#pragma once

#include "CoreMinimal.h"

struct FDiscordRichPresenceActivity;

/**
 * Connexion brute au client Discord local.
 *
 * Discord ecoute sur un named pipe Windows : \\.\pipe\discord-ipc-N (N de 0 a 9,
 * un par instance de Discord lancee). Le protocole est une suite de frames :
 *
 *     [int32 opcode LE][int32 taille LE][payload JSON UTF-8]
 *
 * opcode 0 = HANDSHAKE, 1 = FRAME (commandes), 2 = CLOSE, 3 = PING, 4 = PONG.
 *
 * Aucune DLL ni SDK externe n'est necessaire.
 */
class FDiscordIpcConnection
{
public:
	~FDiscordIpcConnection();

	/** Ouvre le pipe et envoie le handshake. Ne bloque pas si Discord n'est pas lance. */
	bool Connect(const FString& InClientId);

	/** Ferme proprement le pipe. */
	void Disconnect();

	bool IsConnected() const { return PipeHandle != nullptr; }

	/** Vrai une fois que Discord a repondu READY : avant ca, inutile d'envoyer une activite. */
	bool IsReady() const { return bReady; }

	/** Consomme les frames entrantes (READY, erreurs, PING). Retourne false si le pipe est mort. */
	bool Poll();

	/** @param StartUnixTime timestamp de debut de partie, ou 0 pour ne pas afficher le temps ecoule. */
	bool SendActivity(const FDiscordRichPresenceActivity& Activity, int64 StartUnixTime);

	/** Retire le jeu du statut Discord sans fermer la connexion. */
	bool ClearActivity();

private:
	bool WriteFrame(int32 OpCode, const FString& Payload);
	bool ReadExactly(void* Buffer, int32 NumBytes);
	void HandleIncomingFrame(int32 OpCode, const FString& Payload);
	FString BuildActivityPayload(const FDiscordRichPresenceActivity* Activity, int64 StartUnixTime);

	/** HANDLE Win32, garde en void* pour ne pas trainer <Windows.h> dans le header. */
	void* PipeHandle = nullptr;

	FString ClientId;
	bool bReady = false;
	int32 NonceCounter = 0;
};
