#include "PlayerSnake.h"
#include "FoodItem.h"
#include "Kismet/GameplayStatics.h"
#include "DrawDebugHelpers.h"
#include "Blueprint/UserWidget.h"

APlayerSnake::APlayerSnake()
{
    PrimaryActorTick.bCanEverTick = true;
    CurrentDirection = FIntPoint(1, 0);
    bHasInputThisTick = false;
    bIsGhostMode = false;
    Score = 0;
    CurrentMoveSpeed = DefaultMoveSpeed;
}

void APlayerSnake::BeginPlay()
{
    Super::BeginPlay();
    
    if (!GridReference)
    {
        GridReference = Cast<ASnakeGrid>(UGameplayStatics::GetActorOfClass(GetWorld(), ASnakeGrid::StaticClass()));
    }

    // Start-Körper der Schlange
    BodyPoints.Empty();
    BodyPoints.Add(FIntPoint(5, 6));
    BodyPoints.Add(FIntPoint(4, 6));
    BodyPoints.Add(FIntPoint(3, 6));

    SpawnFood();

    // Timer für die Bewegung starten
    GetWorldTimerManager().SetTimer(MoveTimerHandle, this, &APlayerSnake::Move, CurrentMoveSpeed, true);
}

void APlayerSnake::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    if (GridReference)
    {
        for (int32 i = 0; i < BodyPoints.Num(); i++)
        {
            FVector WorldPos = GridReference->GridToWorld(BodyPoints[i].X, BodyPoints[i].Y);
            
            // Farbe ändert sich im Ghost Mode zu Cyan
            FColor Color = bIsGhostMode ? FColor::Cyan : ((i == 0) ? FColor::Yellow : FColor::Green);
            DrawDebugBox(GetWorld(), WorldPos, FVector(GridReference->CellSize * 0.5f), Color, false, -1, 0, 20.0f);
        }
    }
}

void APlayerSnake::Move()
{
    // Bewegung stoppen, wenn das Spiel pausiert ist
    if (!GridReference || UGameplayStatics::IsGamePaused(GetWorld())) return;

    FIntPoint NewHead = BodyPoints[0] + CurrentDirection;

    // Check: Kollision mit der Wand
    if (GridReference->IsOutOfBounds(NewHead))
    {
        HandleGameOver();
        return;
    }

    // Check: Kollision mit sich selbst (ignoriert im Ghost Mode)
    if (!bIsGhostMode)
    {
        for (const FIntPoint& Part : BodyPoints)
        {
            if (Part == NewHead)
            {
                HandleGameOver();
                return;
            }
        }
    }

    // Check: Kollision mit Food-Items
    AFoodItem* EatenFood = nullptr;
    TArray<AActor*> FoundActors;
    UGameplayStatics::GetAllActorsOfClass(GetWorld(), AFoodItem::StaticClass(), FoundActors);

    for (AActor* Actor : FoundActors)
    {
        AFoodItem* Food = Cast<AFoodItem>(Actor);
        if (Food && Food->GridLocation == NewHead)
        {
            EatenFood = Food;
            break;
        }
    }

    if (EatenFood)
    {
        Score += 1000;

        // Effekte je nach Food-Typ
        if (EatenFood->FoodType == EFoodType::SpeedUp)
        {
            CurrentMoveSpeed = 0.08f;
            GetWorldTimerManager().SetTimer(MoveTimerHandle, this, &APlayerSnake::Move, CurrentMoveSpeed, true);
            GetWorldTimerManager().SetTimer(PowerUpTimerHandle, this, &APlayerSnake::ResetSpeed, 5.0f, false);
        }
        else if (EatenFood->FoodType == EFoodType::GhostMode)
        {
            bIsGhostMode = true;
            GetWorldTimerManager().SetTimer(GhostTimerHandle, this, &APlayerSnake::ResetGhostMode, 7.0f, false);
        }

        BodyPoints.Insert(NewHead, 0); // Wachsen
        EatenFood->Destroy();
        SpawnFood();
    }
    else
    {
        // Normale Vorwärtsbewegung
        BodyPoints.Insert(NewHead, 0);
        BodyPoints.RemoveAt(BodyPoints.Num() - 1);
    }

    SetActorLocation(GridReference->GridToWorld(NewHead.X, NewHead.Y));
    bHasInputThisTick = false;
}

void APlayerSnake::HandleGameOver()
{
    // Spiel anhalten
    UGameplayStatics::SetGamePaused(GetWorld(), true);

    // Mauszeiger für UI-Interaktion freigeben
    APlayerController* PC = Cast<APlayerController>(GetController());
    if (PC)
    {
        PC->bShowMouseCursor = true;
        PC->SetInputMode(FInputModeUIOnly());
    }

    // Game-Over Widget anzeigen
    if (GameOverWidgetClass)
    {
        UUserWidget* GOWidget = CreateWidget<UUserWidget>(GetWorld(), GameOverWidgetClass);
        if (GOWidget)
        {
            GOWidget->AddToViewport();
        }
    }
}

void APlayerSnake::ResetSpeed()
{
    CurrentMoveSpeed = DefaultMoveSpeed;
    GetWorldTimerManager().SetTimer(MoveTimerHandle, this, &APlayerSnake::Move, CurrentMoveSpeed, true);
}

void APlayerSnake::ResetGhostMode()
{
    bIsGhostMode = false;
}

void APlayerSnake::SpawnFood()
{
    if (!GetWorld() || !GridReference || FoodClasses.Num() == 0) return;

    FIntPoint RandomLoc(FMath::RandRange(0, GridReference->GridSizeX - 1), FMath::RandRange(0, GridReference->GridSizeY - 1));
    FVector SpawnPos = GridReference->GridToWorld(RandomLoc.X, RandomLoc.Y);
    
    int32 RandomIndex = FMath::RandRange(0, FoodClasses.Num() - 1);
    AFoodItem* NewFood = GetWorld()->SpawnActor<AFoodItem>(FoodClasses[RandomIndex], SpawnPos, FRotator::ZeroRotator);
    
    if (NewFood)
    {
        NewFood->GridLocation = RandomLoc;
    }
}

void APlayerSnake::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);
    PlayerInputComponent->BindAction("MoveUp", IE_Pressed, this, &APlayerSnake::MoveUp);
    PlayerInputComponent->BindAction("MoveDown", IE_Pressed, this, &APlayerSnake::MoveDown);
    PlayerInputComponent->BindAction("MoveLeft", IE_Pressed, this, &APlayerSnake::MoveLeft);
    PlayerInputComponent->BindAction("MoveRight", IE_Pressed, this, &APlayerSnake::MoveRight);
}

void APlayerSnake::MoveUp()    { if (CurrentDirection.Y == 0 && !bHasInputThisTick) { CurrentDirection = FIntPoint(0, 1);  bHasInputThisTick = true; } }
void APlayerSnake::MoveDown()  { if (CurrentDirection.Y == 0 && !bHasInputThisTick) { CurrentDirection = FIntPoint(0, -1); bHasInputThisTick = true; } }
void APlayerSnake::MoveLeft()  { if (CurrentDirection.X == 0 && !bHasInputThisTick) { CurrentDirection = FIntPoint(-1, 0); bHasInputThisTick = true; } }
void APlayerSnake::MoveRight() { if (CurrentDirection.X == 0 && !bHasInputThisTick) { CurrentDirection = FIntPoint(1, 0);  bHasInputThisTick = true; } }