// Copyright 2025 Greyscalegorilla, Inc. 

#pragma once

#include "CoreMinimal.h"
#include "HAL/Runnable.h"

struct SocketClient
{
    FSocket *Socket;
    FString Address;

    bool operator==(const SocketClient &Other)
    {
        return Address == Other.Address;
    }
};

struct FGSGConnectError;
struct FGSGConnectSuccess;

class FGSGSocketsServer : public FRunnable
{
public:
    FGSGSocketsServer(int SelectedPort);
    virtual ~FGSGSocketsServer();

    virtual bool Init() override;
    virtual uint32 Run() override;
    virtual void Stop() override;

private:
    void ReadSocketData(TSharedPtr<SocketClient>);
    void HandleDisconnection(TSharedPtr<SocketClient> Client);
    void ProcessMessage(FSocket *Socket, FString ReceivedMessage);
    void OnPing(FSocket *Socket);
    void OnTaskCompleted(FSocket *Socket);
    void OnSuccess(FGSGConnectSuccess Success);
    void OnError(FGSGConnectError Error);
    void RespondMessage(FSocket *Socket, FString ResponseMessage);
    TSharedPtr<FJsonObject> LoadJSONFromString(FString JsonString);
    FString SerializeGSGConnectErrorsToJson(const TArray<FGSGConnectError> &Errors);
    FString SerializeGSGConnectErrorToJson(const FGSGConnectError &Error);
    FString CreateCompletedJson(const TArray<FGSGConnectSuccess>& Succeses);
    void ShutdownSocketServer();

    FString MessagingVersion;
    FRunnableThread *MyThread;
    bool bStopThread;
    TMap<FString, TSharedPtr<SocketClient>> Clients;
    TArray<FString> ClientsDisconnected;
    int32 ListenPort;
    FString ListenSocketName;
    FSocket *ListenSocket;
    int32 BufferMaxSize;
    TArray<FGSGConnectError> FoundErrors;
    TArray<FGSGConnectSuccess> FoundSucceses;
    FCriticalSection SocketCriticalSection;
};
