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;
import net.minecraft.world.level.pathfinder.Path;

/**
 * AI Goal: NPC patrols around a defined zone.
 *
 * Personality System Phase D: AI Goals
 *
 * <p><b>Behavior:</b></p>
 * <ul>
 *   <li>Only active when NPC has PATROL command</li>
 *   <li>Walks randomly within a radius of the command target</li>
 *   <li>Awards XP periodically while patrolling</li>
 *   <li>Job command - continues until cancelled</li>
 * </ul>
 */
public class NpcPatrolCommandGoal extends Goal {

    private final EntityDamsel npc;
    private final double speedModifier;

    /** Patrol radius around center */
    private static final int PATROL_RADIUS = 10;

    /** Ticks between finding new patrol point */
    private static final int PATROL_INTERVAL_MIN = 100;
    private static final int PATROL_INTERVAL_MAX = 200;

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

    @Nullable
    private BlockPos patrolCenter;

    @Nullable
    private BlockPos currentTarget;

    private int patrolTimer;
    private int xpTimer;

    public NpcPatrolCommandGoal(EntityDamsel npc, double speedModifier) {
        this.npc = npc;
        this.speedModifier = speedModifier;
        this.setFlags(EnumSet.of(Goal.Flag.MOVE));
    }

    @Override
    public boolean canUse() {
        if (npc.getActiveCommand() != NpcCommand.PATROL) {
            return false;
        }
        if (!npc.hasCollar()) {
            return false;
        }

        var state = npc.getPersonalityState();
        if (state == null) return false;

        this.patrolCenter = state.getCommandTarget();
        // If no target set, use current position
        if (this.patrolCenter == null) {
            this.patrolCenter = npc.blockPosition();
        }

        return true;
    }

    @Override
    public boolean canContinueToUse() {
        if (npc.getActiveCommand() != NpcCommand.PATROL) {
            return false;
        }
        if (!npc.hasCollar()) {
            return false;
        }
        return true;
    }

    @Override
    public void start() {
        NpcGoalHelper.ensureOutsideCell(npc);
        this.patrolTimer = 0;
        this.xpTimer = 0;
        this.currentTarget = null;
        findNewPatrolPoint();
    }

    @Override
    public void stop() {
        this.npc.getNavigation().stop();
        this.patrolCenter = null;
        this.currentTarget = null;
    }

    @Override
    public void tick() {
        // Decrement patrol timer
        if (--this.patrolTimer <= 0) {
            findNewPatrolPoint();
        }

        // If we reached the target or got stuck, find new point
        if (this.currentTarget != null) {
            double dist = npc.distanceToSqr(
                currentTarget.getX() + 0.5,
                currentTarget.getY(),
                currentTarget.getZ() + 0.5
            );
            if (dist < 4.0 || npc.getNavigation().isDone()) {
                findNewPatrolPoint();
            }
        }

        // Award XP periodically
        if (++this.xpTimer >= XP_INTERVAL) {
            this.xpTimer = 0;
            awardXP(2);
        }
    }

    /**
     * Find a new random point to patrol to.
     */
    private void findNewPatrolPoint() {
        if (this.patrolCenter == null) return;

        // Random offset within radius
        int dx = npc.getRandom().nextInt(PATROL_RADIUS * 2 + 1) - PATROL_RADIUS;
        int dz = npc.getRandom().nextInt(PATROL_RADIUS * 2 + 1) - PATROL_RADIUS;

        BlockPos target = patrolCenter.offset(dx, 0, dz);

        // Find valid Y level
        for (int dy = 3; dy >= -3; dy--) {
            BlockPos check = target.offset(0, dy, 0);
            if (
                npc.level().getBlockState(check.below()).isSolid() &&
                !npc.level().getBlockState(check).isSolid() &&
                !npc.level().getBlockState(check.above()).isSolid()
            ) {
                target = check;
                break;
            }
        }

        this.currentTarget = target;
        this.patrolTimer =
            PATROL_INTERVAL_MIN +
            npc.getRandom().nextInt(PATROL_INTERVAL_MAX - PATROL_INTERVAL_MIN);

        npc
            .getNavigation()
            .moveTo(
                target.getX() + 0.5,
                target.getY(),
                target.getZ() + 0.5,
                speedModifier
            );
    }

    /**
     * Award XP to the commanding player.
     */
    private void awardXP(int amount) {
        NpcGoalHelper.awardXPToMaster(npc, amount);
    }
}
