#pragma once

#include "CoreMinimal.h"
#include "InputCoreTypes.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "HyperTwistAlgorithm/HyperTwistAlgorithmKeyboard.h"

#include "HyperTwistPlayerSettings.generated.h"

UENUM(BlueprintType)
enum class EHyperTwistGraphicsQuality : uint8
{
	Low,
	Medium,
	High,
	Epic
};

UENUM(BlueprintType)
enum class EHyperTwistWindowMode : uint8
{
	Fullscreen,
	Borderless,
	Windowed
};

USTRUCT(BlueprintType)
struct UNREALHYPERTWIST_API FHyperTwistKeyBindingDescriptor
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings")
	FName ActionId;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings")
	FString Label;

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

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings")
	FKey Key;

	bool IsStructurallyValid() const
	{
		return !ActionId.IsNone() && !Label.IsEmpty() && Key.IsValid();
	}
};

USTRUCT(BlueprintType)
struct UNREALHYPERTWIST_API FHyperTwistDesktopAccountState
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Account")
	bool bLinked = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Account")
	FString Email;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Account")
	FString Plan = TEXT("explorer");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Account")
	FString Role = TEXT("user");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Account")
	bool bCanDownload = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Account")
	FString AccessStatus = TEXT("unlinked");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Account")
	FString LinkedAtUtc;

	bool IsStructurallyValid() const
	{
		return !bLinked || (!Email.IsEmpty() && !Plan.IsEmpty() && !Role.IsEmpty());
	}
};

USTRUCT(BlueprintType)
struct UNREALHYPERTWIST_API FHyperTwistMicrophoneDescriptor
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString DeviceId = TEXT("system-default");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString DisplayName = TEXT("System default microphone");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	bool bIsDefault = false;

	bool IsStructurallyValid() const
	{
		return !DeviceId.IsEmpty() && !DisplayName.IsEmpty();
	}
};

USTRUCT(BlueprintType)
struct UNREALHYPERTWIST_API FHyperTwistPlayerPreferences
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings")
	int32 SchemaVersion = 4;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Controls")
	FString KeyboardProfileId = TEXT("classic-wca-keyboard/v1");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Controls")
	TMap<FName, FKey> KeyBindings;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Controls")
	float PointerSensitivity = 1.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Controls")
	float OrbitSensitivity = 1.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Controls")
	float ZoomSensitivity = 1.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Controls")
	bool bInvertOrbitY = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Controls")
	bool bTouchInputEnabled = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Audio")
	float MasterVolume = 0.85f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Audio")
	float MusicVolume = 0.55f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Audio")
	float EffectsVolume = 0.80f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Audio")
	float VoiceVolume = 0.85f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Audio")
	bool bMuted = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Graphics")
	EHyperTwistGraphicsQuality GraphicsQuality = EHyperTwistGraphicsQuality::High;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Graphics")
	EHyperTwistWindowMode WindowMode = EHyperTwistWindowMode::Borderless;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Graphics")
	float ResolutionScalePercent = 100.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Graphics")
	bool bVSyncEnabled = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Accessibility")
	float UiScale = 1.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Accessibility")
	bool bReducedMotion = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Accessibility")
	bool bHighContrast = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Accessibility")
	bool bSubtitlesEnabled = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	bool bSpeechInputEnabled = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	bool bCoachNarrationEnabled = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	bool bAllowCloudProviders = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString SpeechProviderId = TEXT("local-whisper-cpp");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString SpeechEndpoint = TEXT("http://127.0.0.1:8766");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString SpeechActivationMode = TEXT("hold");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString SpeechDictationDestination = TEXT("coach-draft");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString SpeechModel = TEXT("local-whisper/base-q5_1");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString SpeechLanguage = TEXT("auto");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString SpeechMicrophoneId = TEXT("system-default");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString SpeechRecognitionContext = TEXT("HyperTwist, cubing, hypercube, 120-cell");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	bool bSpeechCleanupEnabled = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	bool bSpeechSoundFeedbackEnabled = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString VoiceProviderId = TEXT("local-piper");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString VoiceEndpoint = TEXT("http://127.0.0.1:8766");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString VoiceModel = TEXT("piper-medium");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	FString VoiceId = TEXT("en_US-lessac-medium");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|Speech")
	float VoiceSpeed = 1.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|AI")
	bool bCoachAiEnabled = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|AI")
	bool bAssistantPanelEnabled = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|AI")
	bool bAssistantPanelOpenByDefault = false;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|AI")
	FString CoachProviderId = TEXT("local-disabled");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|AI")
	FString CoachEndpoint;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|AI")
	FString CoachModel;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|AI")
	FString CoachSystemInstructions =
		TEXT("You are the HyperTwist puzzle coach. Give concise, accurate guidance without inventing puzzle state.");

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|AI")
	float CoachTemperature = 0.2f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|AI")
	int32 CoachMaxResponseTokens = 600;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "HyperTwist|Settings|AI")
	float CoachRequestTimeoutSeconds = 30.0f;

	bool IsStructurallyValid() const;
};

UCLASS()
class UNREALHYPERTWIST_API UHyperTwistPlayerSettingsLibrary
	: public UBlueprintFunctionLibrary
{
	GENERATED_BODY()

public:
	UFUNCTION(BlueprintPure, Category = "HyperTwist|Settings")
	static FHyperTwistPlayerPreferences GetDefaultPreferences();

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Settings")
	static FHyperTwistPlayerPreferences LoadPreferences();

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Settings")
	static bool SavePreferences(const FHyperTwistPlayerPreferences& Preferences);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Settings")
	static void ApplyRuntimePreferences(
		const FHyperTwistPlayerPreferences& Preferences,
		bool bApplyGraphicsSettings
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Settings|Controls")
	static TArray<FHyperTwistKeyBindingDescriptor> BuildKeyBindingDescriptors(
		const FHyperTwistPlayerPreferences& Preferences
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Settings|Controls")
	static TArray<FString> GetSupportedKeyboardProfileIds();

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Settings|Controls")
	static FString GetKeyboardProfileDisplayName(const FString& ProfileId);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Settings|Controls")
	static bool ApplyKeyboardProfile(
		UPARAM(ref) FHyperTwistPlayerPreferences& Preferences,
		const FString& ProfileId
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Settings|Controls")
	static bool TrySetKeyBinding(
		UPARAM(ref) FHyperTwistPlayerPreferences& Preferences,
		FName ActionId,
		FKey NewKey,
		FString& OutFailureReason
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Settings|Controls")
	static FKey ResolveKeyBinding(
		const FHyperTwistPlayerPreferences& Preferences,
		FName ActionId
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Settings|Controls")
	static FHyperTwistAlgorithmKeyboardProfile BuildClassicKeyboardProfile(
		const FHyperTwistPlayerPreferences& Preferences
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Settings|Controls")
	static FName BuildClassicMoveBindingId(
		const FHyperTwistAlgorithmBlockMove& Move
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Settings|Speech")
	static TArray<FHyperTwistMicrophoneDescriptor> GetAvailableMicrophones();

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Settings|Speech")
	static bool TestMicrophoneDevice(
		const FString& DeviceId,
		FString& OutFailureReason
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Account")
	static FHyperTwistDesktopAccountState LoadDesktopAccountState();

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Account")
	static bool SaveDesktopAccountState(const FHyperTwistDesktopAccountState& AccountState);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Account")
	static void ClearDesktopAccountState();

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Settings|Credentials")
	static bool StoreProviderCredential(
		const FString& CredentialSlot,
		const FString& Secret,
		FString& OutFailureReason
	);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Settings|Credentials")
	static bool LoadProviderCredential(
		const FString& CredentialSlot,
		FString& OutSecret
	);

	UFUNCTION(BlueprintPure, Category = "HyperTwist|Settings|Credentials")
	static bool HasProviderCredential(const FString& CredentialSlot);

	UFUNCTION(BlueprintCallable, Category = "HyperTwist|Settings|Credentials")
	static void DeleteProviderCredential(const FString& CredentialSlot);

	static bool IsProviderEndpointAllowed(
		const FString& Endpoint,
		bool bAllowCloudProviders,
		FString& OutFailureReason
	);

	static const TCHAR* GetMainMenuMapAssetPath();
	static const TCHAR* GetMainMenuGameModeClassPath();
	static const TCHAR* GetAccountWebsiteUrl();
	static const TCHAR* GetDesktopLinkVerifyUrl();
};
