#pragma once

#include "CoreMinimal.h"
#include "HAL/PlatformProcess.h"
#include "Misc/Paths.h"
#include "Containers/Ticker.h"
#include "HyperTwistIPCProcessManager.generated.h"

USTRUCT(BlueprintType)
struct FHyperTwistIPCProcessOptions
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|IPC")
    FString ExecutablePath;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|IPC")
    TArray<FString> Arguments;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|IPC")
    FString WorkingDirectory;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|IPC")
    bool bCaptureOutput = true;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|IPC")
    bool bRedirectInput = true;

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|IPC")
    float TimeoutSeconds = 30.0f;
};

USTRUCT(BlueprintType)
struct FHyperTwistIPCResult
{
    GENERATED_BODY()

    UPROPERTY(BlueprintReadOnly, Category = "HyperTwist|IPC")
    bool bSuccess = false;

    UPROPERTY(BlueprintReadOnly, Category = "HyperTwist|IPC")
    FString StdOut;

    UPROPERTY(BlueprintReadOnly, Category = "HyperTwist|IPC")
    FString StdErr;

    UPROPERTY(BlueprintReadOnly, Category = "HyperTwist|IPC")
    int32 ExitCode = -1;

    UPROPERTY(BlueprintReadOnly, Category = "HyperTwist|IPC")
    FString ErrorMessage;
};

UCLASS(ClassGroup = (HyperTwist), meta = (BlueprintSpawnableComponent))
class UNREALHYPERTWIST_API UHyperTwistIPCProcessManager : public UObject
{
    GENERATED_BODY()

public:
    UHyperTwistIPCProcessManager();

    UFUNCTION(BlueprintCallable, Category = "HyperTwist|IPC", meta = (WorldContext = "WorldContextObject"))
    static UHyperTwistIPCProcessManager* CreateIPCManager(UObject* WorldContextObject);

    UFUNCTION(BlueprintCallable, Category = "HyperTwist|IPC")
    FHyperTwistIPCResult RunProcess(const FHyperTwistIPCProcessOptions& Options);

    UFUNCTION(BlueprintCallable, Category = "HyperTwist|IPC")
    int32 StartProcess(const FHyperTwistIPCProcessOptions& Options);

    UFUNCTION(BlueprintCallable, Category = "HyperTwist|IPC")
    bool WriteToProcess(int32 ProcessId, const FString& Line);

    UFUNCTION(BlueprintCallable, Category = "HyperTwist|IPC")
    FString ReadFromProcess(int32 ProcessId);

    UFUNCTION(BlueprintCallable, Category = "HyperTwist|IPC")
    bool TerminateProcess(int32 ProcessId);

    UFUNCTION(BlueprintCallable, Category = "HyperTwist|IPC")
    bool IsProcessRunning(int32 ProcessId);

    static FString GetSolversDirectory();

private:
    struct FActiveProcess
    {
        FProcHandle Handle;
        void* ReadPipe = nullptr;
        void* WritePipe = nullptr;
        float StartTime = 0.0f;
        FString ExecutablePath;
    };

    TMap<int32, FActiveProcess> ActiveProcesses;
    int32 NextProcessId = 1;
};
