#pragma once

#include "CoreMinimal.h"
#include "Components/Widget.h"
#include "HyperTwistBrowser/HyperTwistBrowserBridgeObject.h"
#include "HyperTwistTraining/HyperTwistTrainingTilingLibrary.h"
#include "HyperTwistBrowserWidget.generated.h"

class SWebBrowser;

USTRUCT(BlueprintType)
struct FHyperTwistBrowserOperatorStatusSurface
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString Headline;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString SummaryLine;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString QueueStatusLine;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString BridgeStatusLine;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString ShellAuthorityLine;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	bool bBrowserRuntimeReady = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	bool bHasRuntimeReadyPayload = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	bool bHasRuntimeStatusEnvelope = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString RuntimeStageId;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString RuntimeMode;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString BridgeTrafficStatus;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString BootstrapStartedAtUtc;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString RuntimeReadyAtUtc;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString LastCommandReceivedAtUtc;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString LastShellStateReceivedAtUtc;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString FallbackReason;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	int32 AdapterCount = 0;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	int32 PendingCommandCount = 0;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	int32 PendingShellStateCount = 0;

	bool IsStructurallyValid() const
	{
		return !Headline.IsEmpty() && !SummaryLine.IsEmpty() && !QueueStatusLine.IsEmpty()
			&& !BridgeStatusLine.IsEmpty() && !ShellAuthorityLine.IsEmpty();
	}
};

UCLASS(BlueprintType)
class UNREALHYPERTWIST_API UHyperTwistBrowserWidget : public UWidget
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	bool bUseBundledBrowserShell = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	bool bShowBrowserControls = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Browser")
	FString InitialUrl;

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Browser")
	void LoadBundledBrowserShell();

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Browser")
	void LoadBrowserUrl(const FString& NewUrl);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Browser")
	void DispatchCommandJson(const FString& CommandJson);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Browser")
	void PushShellStateJson(const FString& StateJson);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Browser")
	bool PushTilingStateEnvelope(const FHyperTwistTrainingTilingStateEnvelope& StateEnvelope);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	FString GetLastEnvelopeJson() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	FString GetLastRuntimeReadyJson() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	FString GetLastStateJson() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	int32 GetPendingCommandCount() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	bool HasPendingShellStateJson() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	bool IsBrowserRuntimeReady() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	FHyperTwistBrowserOperatorStatusSurface GetBrowserOperatorStatusSurface() const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	bool TryGetLastTilingEnvelope(
		FHyperTwistTrainingTilingStateEnvelope& OutStateEnvelope
	) const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	bool TryGetLastRuntimeReadyPayload(
		FHyperTwistBrowserRuntimeReadyPayload& OutRuntimeReadyPayload
	) const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	bool TryGetLastTilingStateEnvelope(
		FHyperTwistTrainingTilingStateEnvelope& OutStateEnvelope
	) const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	bool TryGetLastBrowserRuntimeStatusEnvelope(
		FHyperTwistBrowserRuntimeStatusEnvelope& OutStatusEnvelope
	) const;

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	static FString ResolveBundledBrowserShellUrl();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Browser")
	static FString ResolveBundledBrowserShellSourcePath();

protected:
	virtual TSharedRef<SWidget> RebuildWidget() override;
	virtual void ReleaseSlateResources(bool bReleaseChildren) override;
	virtual void SynchronizeProperties() override;
	virtual bool IsBrowserRuntimeDispatchReady() const;
	virtual void ExecuteBrowserRuntimeScript(const FString& Script);

private:
	void HandleBrowserRuntimeReady(const FString& RuntimeReadyJson);
	void FlushPendingBrowserMessages();
	void QueueCommandJson(const FString& CommandJson);
	void QueueShellStateJson(const FString& StateJson);
	void ResetBrowserRuntimeHandshake();
	void EnsureBridgeObject();
	FString BuildCommandDispatchScript(const FString& CommandJson) const;
	FString BuildShellStateDispatchScript(const FString& StateJson) const;
	static FString EscapeForJavaScriptSingleQuotedString(const FString& Input);
	FString ResolveInitialUrl() const;
	void EnsureBridgeBound();

	UPROPERTY(Transient)
	TObjectPtr<UHyperTwistBrowserBridgeObject> BrowserBridgeObject = nullptr;

	UPROPERTY(Transient)
	TArray<FString> PendingCommandJsonQueue;

	UPROPERTY(Transient)
	FString PendingShellStateJson;

	UPROPERTY(Transient)
	bool bHasPendingShellStateJson = false;

	UPROPERTY(Transient)
	bool bBrowserRuntimeReady = false;

	TSharedPtr<SWebBrowser> BrowserWidget;
	FDelegateHandle RuntimeReadyDelegateHandle;

#if WITH_AUTOMATION_TESTS
public:
	void SetBrowserRuntimeDispatchReadyForTesting(bool bInDispatchReady);
	void SimulateBrowserEnvelopeForTesting(const FString& EnvelopeJson);
	void SimulateBrowserRuntimeReadyForTesting(const FString& RuntimeReadyJson);
	const TArray<FString>& GetExecutedBrowserScriptsForTesting() const;

private:
	bool bForceBrowserRuntimeDispatchReadyForTesting = false;
	TArray<FString> ExecutedBrowserScriptsForTesting;
#endif
};
