// Copyright Pacificao. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "AgrarianTypes.h"
#include "AgrarianBuildingPlacementComponent.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAgrarianBuildPlacedSignature, AActor*, PlacedActor);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAgrarianBuildPlacementFailedSignature, FText, Reason);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FAgrarianBuildPreviewUpdatedSignature, bool, bCanPlace, FTransform, PreviewTransform, FText, FailureReason);

UCLASS(ClassGroup = (Agrarian), BlueprintType, Blueprintable, meta = (BlueprintSpawnableComponent))
class UAgrarianBuildingPlacementComponent : public UActorComponent
{
	GENERATED_BODY()

public:
	UAgrarianBuildingPlacementComponent();

	UPROPERTY(BlueprintAssignable, Category = "Agrarian|Building")
	FAgrarianBuildPlacedSignature OnBuildPlaced;

	UPROPERTY(BlueprintAssignable, Category = "Agrarian|Building")
	FAgrarianBuildPlacementFailedSignature OnBuildPlacementFailed;

	UPROPERTY(BlueprintAssignable, Category = "Agrarian|Building")
	FAgrarianBuildPreviewUpdatedSignature OnBuildPreviewUpdated;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building")
	TSubclassOf<AActor> ActiveBuildClass;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building")
	TArray<FAgrarianItemStack> PlacementCost;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building", meta = (ClampMin = "100"))
	float PlacementDistance = 600.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building", meta = (ClampMin = "0"))
	float PlacementProbeRadius = 75.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building", meta = (ClampMin = "0"))
	float SurfaceOffset = 2.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building")
	bool bSnapToGrid = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building", meta = (EditCondition = "bSnapToGrid", ClampMin = "1"))
	float GridSize = 50.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building|Preview")
	bool bShowGhostPreview = true;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building|Preview", meta = (ClampMin = "0"))
	float GhostPreviewLifetimeSeconds = 0.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building|Preview", meta = (ClampMin = "0"))
	float GhostPreviewLineThickness = 2.0f;

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building|Preview")
	FColor ValidGhostPreviewColor = FColor(70, 220, 120);

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Agrarian|Building|Preview")
	FColor InvalidGhostPreviewColor = FColor(230, 80, 65);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Building")
	void SetActiveBuildable(TSubclassOf<AActor> BuildClass, const TArray<FAgrarianItemStack>& Cost);

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Building")
	bool GetPlacementPreview(FTransform& OutTransform, FText& FailureReason) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Building")
	bool GetPlacementPreviewState(FTransform& OutTransform, FText& FailureReason) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Building")
	bool CanPlaceAtTransform(TSubclassOf<AActor> BuildClass, const FTransform& PlacementTransform, FText& FailureReason) const;

	UFUNCTION(BlueprintCallable, Category = "Agrarian|Building")
	bool PlaceActiveBuildable();

	UFUNCTION(Server, Reliable, BlueprintCallable, Category = "Agrarian|Building")
	void ServerPlaceBuildable(TSubclassOf<AActor> BuildClass, FTransform PlacementTransform);

	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

protected:
	bool HasPlacementCost(FText& FailureReason) const;
	void ConsumePlacementCost();
	void FailPlacement(const FText& Reason);
	FVector SnapLocation(const FVector& Location) const;
};
