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

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityDamsel;
import com.tiedup.remake.personality.HomeType;
import com.tiedup.remake.personality.NpcCommand;
import com.tiedup.remake.personality.NpcNeeds;
import com.tiedup.remake.personality.PersonalityState;
import java.util.EnumSet;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.ai.goal.Goal;

/**
 * AI Goal: NPC automatically goes home to rest when tired.
 *
 * <p>Triggers when:
 * <ul>
 *   <li>Auto-rest is enabled</li>
 *   <li>Rest drops below 30 (tired)</li>
 *   <li>NPC has an assigned home</li>
 * </ul>
 *
 * <p>Behavior:
 * <ul>
 *   <li>Saves current command</li>
 *   <li>Walks to home position</li>
 *   <li>Rests until rest >= 70 (rested)</li>
 *   <li>Restores previous command</li>
 * </ul>
 *
 * <p>Priority: 2 (passive goal, doesn't block other goals until moving)
 */
public class NpcAutoRestGoal extends Goal {

    private final EntityDamsel npc;

    /** Rest level below which NPC seeks rest */
    private static final float TIRED_THRESHOLD = 30.0f;

    /** Rest level to reach before stopping rest */
    private static final float RESTED_THRESHOLD = 70.0f;

    /** Critical exhaustion - higher priority */
    private static final float CRITICAL_THRESHOLD = 10.0f;

    /** Distance considered "arrived" at home */
    private static final double ARRIVAL_DISTANCE_SQ = 4.0; // 2 blocks squared

    /** Ticks between rest recovery ticks */
    private static final int REST_TICK_INTERVAL = 20;

    private enum RestPhase {
        /** Checking if we should rest */
        CHECKING,
        /** Walking to home position */
        MOVING_TO_HOME,
        /** Resting at home */
        RESTING,
        /** Done resting */
        DONE,
    }

    private RestPhase phase = RestPhase.CHECKING;
    private NpcCommand previousCommand;
    private UUID previousCommandingPlayer;
    private BlockPos previousCommandTarget;
    private BlockPos homePos;
    private BlockPos navigationTarget;
    private int restTimer = 0;

    public NpcAutoRestGoal(EntityDamsel npc) {
        this.npc = npc;
        // Start as passive goal (no flags)
        this.setFlags(EnumSet.noneOf(Goal.Flag.class));
    }

    @Override
    public boolean canUse() {
        PersonalityState state = npc.getPersonalityState();
        if (state == null) return false;

        // Check if auto-rest is enabled
        if (!state.isAutoRestEnabled()) {
            return false;
        }

        NpcNeeds needs = state.getNeeds();

        // Check if tired
        if (needs.getRest() >= TIRED_THRESHOLD) {
            return false;
        }

        // Check if NPC has a home
        if (!state.hasHome()) {
            return false;
        }

        // Don't start if already at home and IDLE (will rest naturally)
        if (state.getActiveCommand() == NpcCommand.IDLE) {
            BlockPos currentHome = state.getHomePos();
            if (
                currentHome != null &&
                npc.distanceToSqr(
                    currentHome.getX() + 0.5,
                    currentHome.getY(),
                    currentHome.getZ() + 0.5
                ) <
                ARRIVAL_DISTANCE_SQ
            ) {
                return false;
            }
        }

        return true;
    }

    @Override
    public boolean canContinueToUse() {
        PersonalityState state = npc.getPersonalityState();
        if (state == null) return false;

        // Stop if auto-rest was disabled
        if (!state.isAutoRestEnabled()) {
            return false;
        }

        // Continue until rested
        if (state.getNeeds().getRest() >= RESTED_THRESHOLD) {
            return false;
        }

        // Continue if not done
        return phase != RestPhase.DONE;
    }

    @Override
    public void start() {
        PersonalityState state = npc.getPersonalityState();
        if (state == null) return;

        // Save current command for restoration later
        this.previousCommand = state.getActiveCommand();
        this.previousCommandingPlayer = state.getCommandingPlayer();
        this.previousCommandTarget = state.getCommandTarget();
        this.homePos = state.getHomePos();
        this.navigationTarget = NpcGoalHelper.getHomeNavigationTarget(npc);

        TiedUpMod.LOGGER.debug(
            "[NpcAutoRestGoal] {} starting auto-rest, saving command: {}",
            npc.getNpcName(),
            previousCommand
        );

        // Start checking
        this.phase = RestPhase.CHECKING;
        this.restTimer = 0;
    }

    @Override
    public void stop() {
        // Teleport outside cell if inside
        NpcGoalHelper.ensureOutsideCell(npc);

        PersonalityState state = npc.getPersonalityState();

        // Restore previous command if we have one and it wasn't GO_HOME
        if (
            state != null &&
            previousCommand != null &&
            previousCommand != NpcCommand.GO_HOME
        ) {
            // Only restore if currently IDLE (we set it during resting)
            if (state.getActiveCommand() == NpcCommand.IDLE) {
                state.setActiveCommand(
                    previousCommand,
                    previousCommandingPlayer,
                    previousCommandTarget
                );
                TiedUpMod.LOGGER.debug(
                    "[NpcAutoRestGoal] {} restored command: {}",
                    npc.getNpcName(),
                    previousCommand
                );
            }
        }

        // Reset rest pose
        npc.setSitting(false);
        npc.setKneeling(false);

        // Reset state
        this.phase = RestPhase.CHECKING;
        this.previousCommand = null;
        this.previousCommandingPlayer = null;
        this.previousCommandTarget = null;
        this.homePos = null;
        this.navigationTarget = null;
        this.restTimer = 0;

        // Remove MOVE flag
        this.setFlags(EnumSet.noneOf(Goal.Flag.class));
        npc.getNavigation().stop();
    }

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

    @Override
    public void tick() {
        switch (phase) {
            case CHECKING -> tickChecking();
            case MOVING_TO_HOME -> tickMoving();
            case RESTING -> tickResting();
            case DONE -> {
            } // Do nothing, will be stopped
        }
    }

    private void tickChecking() {
        PersonalityState state = npc.getPersonalityState();
        if (state == null || homePos == null) {
            phase = RestPhase.DONE;
            return;
        }

        // Check distance to navigation target (deliveryPoint or homePos)
        double distanceSq = npc.distanceToSqr(
            navigationTarget.getX() + 0.5,
            navigationTarget.getY(),
            navigationTarget.getZ() + 0.5
        );

        if (distanceSq < ARRIVAL_DISTANCE_SQ) {
            // Already at home - start resting
            phase = RestPhase.RESTING;
            restTimer = 0;
            npc.getNavigation().stop();

            // Teleport inside cell if navigated to delivery point
            if (homePos != null && !navigationTarget.equals(homePos)) {
                NpcGoalHelper.teleportTo(npc, homePos);
            }

            // Set to IDLE while resting
            state.setActiveCommand(NpcCommand.IDLE, null, homePos);
            applyRestPose();

            TiedUpMod.LOGGER.debug(
                "[NpcAutoRestGoal] {} already at home, starting rest",
                npc.getNpcName()
            );
        } else {
            // Need to walk home
            phase = RestPhase.MOVING_TO_HOME;

            // Set MOVE flag now that we're navigating
            this.setFlags(EnumSet.of(Goal.Flag.MOVE));

            // Start navigation
            npc
                .getNavigation()
                .moveTo(
                    navigationTarget.getX() + 0.5,
                    navigationTarget.getY(),
                    navigationTarget.getZ() + 0.5,
                    1.0
                );

            TiedUpMod.LOGGER.debug(
                "[NpcAutoRestGoal] {} walking home to rest (distance: {})",
                npc.getNpcName(),
                Math.sqrt(distanceSq)
            );
        }
    }

    private void tickMoving() {
        if (homePos == null) {
            phase = RestPhase.DONE;
            return;
        }

        // Check if arrived at navigation target
        double distanceSq = npc.distanceToSqr(
            navigationTarget.getX() + 0.5,
            navigationTarget.getY(),
            navigationTarget.getZ() + 0.5
        );

        if (distanceSq < ARRIVAL_DISTANCE_SQ) {
            // Arrived at home - start resting
            phase = RestPhase.RESTING;
            restTimer = 0;
            npc.getNavigation().stop();

            // Teleport inside cell if navigated to delivery point
            if (homePos != null && !navigationTarget.equals(homePos)) {
                NpcGoalHelper.teleportTo(npc, homePos);
            }

            // Remove MOVE flag during rest
            this.setFlags(EnumSet.noneOf(Goal.Flag.class));

            // Set to IDLE while resting
            PersonalityState state = npc.getPersonalityState();
            if (state != null) {
                state.setActiveCommand(NpcCommand.IDLE, null, homePos);
                applyRestPose();
            }

            TiedUpMod.LOGGER.debug(
                "[NpcAutoRestGoal] {} arrived home, starting rest",
                npc.getNpcName()
            );
        } else {
            // Still moving - keep navigation going
            if (npc.getNavigation().isDone()) {
                // Path finished but not there - try again
                npc
                    .getNavigation()
                    .moveTo(
                        navigationTarget.getX() + 0.5,
                        navigationTarget.getY(),
                        navigationTarget.getZ() + 0.5,
                        1.0
                    );
            }
        }
    }

    private void tickResting() {
        restTimer++;

        // Only process rest every interval
        if (restTimer % REST_TICK_INTERVAL != 0) {
            return;
        }

        PersonalityState state = npc.getPersonalityState();
        if (state == null) {
            phase = RestPhase.DONE;
            return;
        }

        NpcNeeds needs = state.getNeeds();
        float currentRest = needs.getRest();

        // Check if rested enough
        if (currentRest >= RESTED_THRESHOLD) {
            TiedUpMod.LOGGER.debug(
                "[NpcAutoRestGoal] {} finished resting (rest: {})",
                npc.getNpcName(),
                currentRest
            );
            phase = RestPhase.DONE;
            return;
        }

        // The actual rest recovery is handled by NpcNeeds.tick()
        // We just need to keep the NPC at home in IDLE state
    }

    /**
     * Apply appropriate rest pose based on home type.
     */
    private void applyRestPose() {
        PersonalityState state = npc.getPersonalityState();
        if (state == null) return;

        switch (state.getHomeType()) {
            case BED, PET_BED -> npc.setSitting(true);
            case CELL -> npc.setKneeling(true);
            default -> {
            } // NONE - no pose
        }
    }

    /**
     * Get the priority adjustment based on exhaustion level.
     * More tired = higher effective priority.
     *
     * @return Priority modifier (lower = more urgent)
     */
    public int getAdjustedPriority() {
        PersonalityState state = npc.getPersonalityState();
        if (state == null) return 2;

        float rest = state.getNeeds().getRest();
        if (rest < CRITICAL_THRESHOLD) {
            return 1; // Critical exhaustion - very high priority
        }
        return 2; // Normal tired priority
    }
}
