package com.tiedup.remake.entities.ai.personality;

import com.tiedup.remake.entities.EntityDamsel;
import com.tiedup.remake.personality.NpcCommand;
import java.util.EnumSet;
import java.util.UUID;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.player.Player;

/**
 * AI Goal: NPC stays in place when STAY command is active.
 *
 * Personality System Phase D: AI Goals
 *
 * <p><b>Behavior:</b></p>
 * <ul>
 *   <li>Only active when NPC has STAY command</li>
 *   <li>NPC stays at their current position</li>
 *   <li>Cancels other movement goals</li>
 *   <li>Awards training XP periodically while staying</li>
 * </ul>
 */
public class NpcStayCommandGoal extends Goal {

    private final EntityDamsel npc;

    /** Ticks between XP awards */
    private static final int XP_INTERVAL = 2400; // 2 minutes

    /** Maximum allowed drift from stay position */
    private static final double MAX_DRIFT = 3.0;

    @Nullable
    private BlockPos stayPosition;

    private int xpTimer;

    public NpcStayCommandGoal(EntityDamsel npc) {
        this.npc = npc;
        this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.JUMP));
    }

    @Override
    public boolean canUse() {
        // Must have STAY command active
        if (npc.getActiveCommand() != NpcCommand.STAY) {
            return false;
        }

        // Must have collar
        if (!npc.hasCollar()) {
            return false;
        }

        return true;
    }

    @Override
    public boolean canContinueToUse() {
        // Stop if command changed
        if (npc.getActiveCommand() != NpcCommand.STAY) {
            return false;
        }

        // Stop if no collar
        if (!npc.hasCollar()) {
            return false;
        }

        return true;
    }

    @Override
    public void start() {
        // Record current position as stay position
        this.stayPosition = this.npc.blockPosition();
        this.xpTimer = 0;

        // Stop all movement
        this.npc.getNavigation().stop();
    }

    @Override
    public void stop() {
        this.stayPosition = null;
    }

    @Override
    public void tick() {
        // Stop any navigation attempts
        if (this.npc.getNavigation().isInProgress()) {
            this.npc.getNavigation().stop();
        }

        // Check if drifted too far from stay position
        if (this.stayPosition != null) {
            double distSq = this.npc.distanceToSqr(
                this.stayPosition.getX() + 0.5,
                this.stayPosition.getY(),
                this.stayPosition.getZ() + 0.5
            );

            // If drifted, try to return
            if (distSq > MAX_DRIFT * MAX_DRIFT) {
                this.npc.getNavigation().moveTo(
                    this.stayPosition.getX() + 0.5,
                    this.stayPosition.getY(),
                    this.stayPosition.getZ() + 0.5,
                    1.0
                );
            }
        }

        // Award XP periodically for staying
        if (++this.xpTimer >= XP_INTERVAL) {
            this.xpTimer = 0;

            // Find commanding player for XP
            var state = this.npc.getPersonalityState();
            if (state != null) {
                UUID commanderUUID = state.getCommandingPlayer();
                if (commanderUUID != null) {
                    for (Player player : this.npc.level().players()) {
                        if (player.getUUID().equals(commanderUUID)) {
                            break;
                        }
                    }
                }
            }
        }
    }

    @Override
    public boolean requiresUpdateEveryTick() {
        return true;
    }
}
