// © 2025 Naked People Team. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "InputAction.h"
#include "InputMappingContext.h"
#include "NakedDesire/Global/Gait.h"
#include "NakedDesire/Global/NakedDesireUserSettings.h"
#include "NakedDesire/Global/Stance.h"
#include "Perception/AISightTargetInterface.h"
#include "NakedDesireCharacter.generated.h"

class UAIPerceptionStimuliSourceComponent;
class UClothingList;
struct FClothingSlotData;
class UInteractionManager;
class UClothingPickerWidget;
class UClothingManager;
class UStatsManager;
class UMissionsManager;
class ANPCAIController;
class ULocationData;

DECLARE_MULTICAST_DELEGATE_OneParam(FOnNoticedSignature, ANPCAIController*);
DECLARE_MULTICAST_DELEGATE_OneParam(FOnAreaChangeSignature, ULocationData*);

UCLASS(config=Game)
class ANakedDesireCharacter : public ACharacter, public IAISightTargetInterface
{
	GENERATED_BODY()

public:
	ANakedDesireCharacter();

	// Input
	UPROPERTY(EditDefaultsOnly, Category = "Input")
	UInputMappingContext* MappingContext;
	
	UPROPERTY(EditDefaultsOnly, Category = "Input")
	UInputAction* LookAction;
	
	UPROPERTY(EditDefaultsOnly, Category = "Input")
	UInputAction* MoveAction;
	
	UPROPERTY(EditDefaultsOnly, Category = "Input")
	UInputAction* RunAction;
	
	UPROPERTY(EditDefaultsOnly, Category = "Input")
	UInputAction* CrouchAction;

	// Clothing
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* NipplesMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* AnalMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* VaginaMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* HeadMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* NeckMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* FaceMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* EyesMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* BodyMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* TopMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* BottomMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* BraMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* PantiesMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* SocksMeshComponent;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	USkeletalMeshComponent* ShoesMeshComponent;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
	UStaticMeshComponent* BoobLCensorship;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
	UStaticMeshComponent* BoobRCensorship;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
	UStaticMeshComponent* FrontBottomCensorship;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Censorship")
	UStaticMeshComponent* BackBottomCensorship;

	// Components
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Clothing")
	UClothingManager* ClothingManager;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	UStatsManager* StatsManager;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	UMissionsManager* MissionsManager;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	UInteractionManager* InteractionManager;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	UAIPerceptionStimuliSourceComponent* StimuliSourceComponent;
	
	// Variables
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	float WalkSpeed = 250.0f;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
	float RunSpeed = 500.0f;

	UPROPERTY(BlueprintReadWrite)
	int Money = 0;
	
	int XP = 0;

	UPROPERTY()
	ULocationData* CurrentArea = nullptr;

	FOnNoticedSignature OnNoticed;

	FOnAreaChangeSignature OnAreaEnter;
	FOnAreaChangeSignature OnAreaExit;

	void NotifyNoticed(ANPCAIController* NPCController);
	void SetIsRunning(bool Value);

	UFUNCTION(BlueprintPure)
	EGait GetGait() const;

	UFUNCTION(BlueprintPure)
	EStance GetStance() const;

	virtual void Tick(float DeltaTime) override;
	virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override;
	virtual void NotifyControllerChanged() override;
	virtual void BeginPlay() override;
	virtual UAISense_Sight::EVisibilityResult CanBeSeenFrom(const FCanBeSeenFromContext& Context, FVector& OutSeenLocation, int32& OutNumberOfLoSChecksPerformed, int32& OutNumberOfAsyncLosCheckRequested, float& OutSightStrength, int32* UserData = nullptr, const FOnPendingVisibilityQueryProcessedDelegate* Delegate = nullptr) override;
	
private:
	EGait Gait = EGait::Walk;
	EStance Stance = EStance::Stand;
	
	UFUNCTION()
	void OnBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp,
		int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

	UFUNCTION()
	void OnEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp,
		int32 OtherBodyIndex);

	UFUNCTION()
	void OnClothingEquip(const UClothingItemInstance* ClothingItemInstance);

	UFUNCTION()
	void OnClothingUnequip(const UClothingItemInstance* ClothingItemInstance);
	
	UFUNCTION()
	void OnSettingsChanged(UNakedDesireUserSettings* Settings);

	void OnLook(const FInputActionValue& Value);
	void OnMove(const FInputActionValue& Value);
	void OnRunPress(const FInputActionValue& Value);
	void OnRunRelease(const FInputActionValue& Value);
	void OnCrouchToggle(const FInputActionValue& Value);

	void SetupClothingSlots();

	bool CheckSight(const FVector& StartLocation, const FVector& EndLocation, FHitResult& HitResult, const AActor* IgnoreActor);
};
