package com.tiedup.remake.entities.ai.maid.goals;

import com.tiedup.remake.cells.CellDataV2;
import com.tiedup.remake.cells.CellRegistryV2;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityMaid;
import com.tiedup.remake.entities.ai.WaypointNavigator;
import com.tiedup.remake.labor.LaborTask;
import com.tiedup.remake.prison.LaborRecord;
import com.tiedup.remake.prison.PrisonerManager;
import com.tiedup.remake.prison.PrisonerRecord;
import com.tiedup.remake.prison.PrisonerState;
import com.tiedup.remake.prison.RansomRecord;
import com.tiedup.remake.prison.service.BondageService;
import com.tiedup.remake.prison.service.ItemService;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.state.ICaptor;
import com.tiedup.remake.util.KidnappedHelper;
import com.tiedup.remake.util.KidnapperAIHelper;
import com.tiedup.remake.util.MessageDispatcher;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.item.ItemStack;

/**
 * Goal: Return prisoners to cells after labor.
 *
 * Flow:
 * 1. Detect prisoner in PENDING_RETURN within 20 blocks of maid
 * 2. Walk to prisoner
 * 3. Leash prisoner (getCapturedBy)
 * 4. Walk to cell, prisoner follows via leash traction
 * 5. At cell: collect items, restore bondage, credit earnings
 * 6. Transition to IMPRISONED/RESTING
 */
public class MaidReturnGoal extends Goal {

    /** Maid detects prisoner returning from task within this radius */
    private static final double DETECTION_RADIUS = 20.0;
    /** Distance to leash the prisoner */
    private static final double LEASH_REACH = 3.0;
    /** Distance to cell to consider arrival */
    private static final double CELL_REACH_DISTANCE = 4.0;
    private static final int MAX_DURATION_TICKS = 6000; // 5 minutes
    private static final long GRACE_PERIOD_TICKS = 6000; // 5 minutes protection
    private static final int STUCK_TELEPORT_TICKS = 200; // 10s stuck → teleport

    private enum Phase {
        /** Walking toward prisoner to leash them */
        APPROACHING_PRISONER,
        /** Leashed prisoner, walking to cell */
        WALKING_TO_CELL,
    }

    private final EntityMaid maid;

    // Current return state
    private Phase phase;
    private UUID targetPrisonerId;
    private BlockPos targetCellPos;
    private int ticksActive;
    private boolean navigationStarted;
    private int stuckTicks;
    private BlockPos lastProgressPos;
    private boolean leashed;
    private CellDataV2 targetCell;
    private WaypointNavigator waypointNav;

    public MaidReturnGoal(EntityMaid maid) {
        this.maid = maid;
        this.setFlags(EnumSet.of(Flag.MOVE, Flag.LOOK));
    }

    @Override
    public boolean canUse() {
        if (maid.isFreed() || maid.isTiedUp()) {
            return false;
        }
        if (maid.getMasterTraderUUID() == null) {
            return false;
        }
        if (maid.getMaidState().isBusy()) {
            return false;
        }
        if (!(maid.level() instanceof ServerLevel level)) {
            return false;
        }

        UUID campId = maid.getCampUUID();
        if (campId == null) {
            return false;
        }

        // Find a prisoner needing return AND within detection radius of the maid
        PrisonerManager manager = PrisonerManager.get(level);
        Set<UUID> prisoners = manager.getPrisonersInCampWithState(
            campId,
            PrisonerState.WORKING
        );

        for (UUID prisonerId : prisoners) {
            LaborRecord labor = manager.getLaborRecord(prisonerId);
            if (labor.getPhase() == LaborRecord.WorkPhase.PENDING_RETURN) {
                ServerPlayer prisoner = level
                    .getServer()
                    .getPlayerList()
                    .getPlayer(prisonerId);
                if (prisoner != null && prisoner.isAlive()) {
                    double distance = maid.distanceTo(prisoner);
                    if (distance <= DETECTION_RADIUS) {
                        PrisonerRecord record = manager.getRecord(prisonerId);
                        UUID cellId = record.getCellId();
                        if (cellId != null) {
                            CellDataV2 cell = CellRegistryV2.get(level).getCell(
                                cellId
                            );
                            if (cell != null) {
                                this.targetPrisonerId = prisonerId;
                                this.targetCell = cell;
                                this.targetCellPos =
                                    KidnapperAIHelper.getDeliveryOrSpawnPoint(
                                        cell,
                                        level
                                    );
                                return true;
                            }
                        }
                    }
                }
            }
        }

        return false;
    }

    @Override
    public void start() {
        ticksActive = 0;
        phase = Phase.APPROACHING_PRISONER;
        navigationStarted = false;
        stuckTicks = 0;
        lastProgressPos = null;
        leashed = false;

        // Build waypoint path if cell has waypoints (same pattern as KidnapperBringToCellGoal)
        if (targetCell != null && !targetCell.getPathWaypoints().isEmpty()) {
            List<BlockPos> fullPath = new ArrayList<>(
                targetCell.getPathWaypoints()
            );
            fullPath.add(targetCellPos); // delivery/spawn as final waypoint
            this.waypointNav = new WaypointNavigator(maid, fullPath, 1.0);
            TiedUpMod.LOGGER.debug(
                "[MaidReturnGoal] {} using {} waypoints for navigation to cell",
                maid.getNpcName(),
                fullPath.size()
            );
        } else {
            this.waypointNav = null;
        }

        maid.setMaidState(
            com.tiedup.remake.entities.ai.maid.MaidState.RETURNING_PRISONER
        );

        TiedUpMod.LOGGER.info(
            "[MaidReturnGoal] {} approaching prisoner {} for return escort",
            maid.getNpcName(),
            targetPrisonerId != null
                ? targetPrisonerId.toString().substring(0, 8)
                : "null"
        );
    }

    @Override
    public void tick() {
        ticksActive++;

        if (!(maid.level() instanceof ServerLevel level)) {
            return;
        }

        if (ticksActive > MAX_DURATION_TICKS) {
            TiedUpMod.LOGGER.warn("[MaidReturnGoal] Return timed out");
            return; // canContinueToUse will stop the goal
        }

        ServerPlayer prisoner = level
            .getServer()
            .getPlayerList()
            .getPlayer(targetPrisonerId);
        if (prisoner == null || !prisoner.isAlive()) {
            TiedUpMod.LOGGER.warn("[MaidReturnGoal] Prisoner offline or dead");
            return;
        }

        switch (phase) {
            case APPROACHING_PRISONER:
                tickApproachPrisoner(level, prisoner);
                break;
            case WALKING_TO_CELL:
                tickWalkToCell(level, prisoner);
                break;
        }
    }

    /**
     */
    private void tickApproachPrisoner(
        ServerLevel level,
        ServerPlayer prisoner
    ) {
        maid.getLookControl().setLookAt(prisoner, 30.0f, 30.0f);

        double distance = maid.distanceTo(prisoner);

        if (distance <= LEASH_REACH) {
            // Close enough — leash the prisoner
            performLeash(level, prisoner);
            phase = Phase.WALKING_TO_CELL;
            navigationStarted = false;
            stuckTicks = 0;
            lastProgressPos = null;
            return;
        }

        // Navigate toward prisoner — re-path every 20 ticks
        if (!navigationStarted || ticksActive % 20 == 0) {
            maid.getNavigation().moveTo(prisoner, 1.0);
            navigationStarted = true;
        }

        // Stuck detection: teleport maid to prisoner if stuck
        tickStuckDetection(prisoner.blockPosition());
    }

    /**
     * Uses WaypointNavigator if path waypoints are defined, else vanilla pathfinding.
     */
    private void tickWalkToCell(ServerLevel level, ServerPlayer prisoner) {
        if (targetCellPos == null) return;

        if (waypointNav != null && waypointNav.hasWaypoints()) {
            // === WAYPOINT MODE ===
            waypointNav.tick();

            if (waypointNav.isComplete()) {
                collectAndReturn(level, prisoner);
                return;
            }

            // Re-path to current waypoint every 20 ticks
            if (!navigationStarted || ticksActive % 20 == 0) {
                waypointNav.navigateToCurrentWaypoint();
                navigationStarted = true;
            }

            // Look at current waypoint
            BlockPos currentWp = waypointNav.getCurrentWaypoint();
            if (currentWp != null) {
                maid
                    .getLookControl()
                    .setLookAt(
                        currentWp.getX() + 0.5,
                        currentWp.getY() + 1,
                        currentWp.getZ() + 0.5
                    );
            }

            // Stuck detection toward current waypoint (not final destination)
            tickStuckDetection(currentWp != null ? currentWp : targetCellPos);
        } else {
            // === VANILLA FALLBACK ===
            // Navigate to cell — re-path every 40 ticks
            if (!navigationStarted || ticksActive % 40 == 0) {
                maid
                    .getNavigation()
                    .moveTo(
                        targetCellPos.getX() + 0.5,
                        targetCellPos.getY(),
                        targetCellPos.getZ() + 0.5,
                        1.0
                    );
                navigationStarted = true;
            }

            // Check if reached cell
            double cellDistance = maid
                .position()
                .distanceTo(
                    new net.minecraft.world.phys.Vec3(
                        targetCellPos.getX() + 0.5,
                        targetCellPos.getY(),
                        targetCellPos.getZ() + 0.5
                    )
                );

            if (cellDistance <= CELL_REACH_DISTANCE) {
                collectAndReturn(level, prisoner);
                return;
            }

            // Stuck detection toward final destination
            tickStuckDetection(targetCellPos);
        }
    }

    /**
     * Bind + leash the prisoner and despawn the guard (maid takes over escort).
     *
     * getCapturedBy requires isEnslavable() (= isTiedUp), but during labor
     * restraints were removed. Re-apply wrist binds from the bondage snapshot
     * first so the leash can attach.
     */
    private void performLeash(ServerLevel level, ServerPlayer prisoner) {
        IBondageState cap = KidnappedHelper.getKidnappedState(prisoner);
        if (cap == null) return;

        PrisonerManager manager = PrisonerManager.get(level);
        LaborRecord labor = manager.getLaborRecord(targetPrisonerId);

        // 1. Re-apply wrist binds from bondage snapshot (makes isEnslavable() = true)
        CompoundTag snapshot = labor.getBondageSnapshot();
        if (snapshot != null && snapshot.contains("BindItem")) {
            ItemStack bind = ItemStack.of(snapshot.getCompound("BindItem"));
            if (!bind.isEmpty()) {
                cap.equip(BodyRegionV2.ARMS, bind);
            }
        } else {
            // Fallback: use basic rope if no snapshot
            cap.equip(
                BodyRegionV2.ARMS,
                com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem.createStack(
                    net.minecraft.resources.ResourceLocation.fromNamespaceAndPath("tiedup", "ropes")
                )
            );
        }

        // 2. Leash — now works because player is tied up
        boolean success = cap.getCapturedBy((ICaptor) maid);
        if (success) {
            leashed = true;
        } else {
            TiedUpMod.LOGGER.warn(
                "[MaidReturnGoal] getCapturedBy failed for {} — fallback direct leash",
                prisoner.getName().getString()
            );
            // Fallback: direct leash attachment bypassing captivity checks
            if (
                prisoner instanceof
                    com.tiedup.remake.state.IPlayerLeashAccess access
            ) {
                access.tiedup$attachLeash(maid);
                leashed = true;
            }
        }

        // 3. Despawn guard — maid takes over escort
        despawnGuard(level, labor);

        // 4. Transition labor phase to RETURNING
        labor.startReturn(maid.getUUID(), level.getGameTime());

        maidSay(
            prisoner,
            "maid.labor.leash",
            "Come with me. Back to your cell."
        );

        TiedUpMod.LOGGER.info(
            "[MaidReturnGoal] {} bound and leashed prisoner {}, escorting to cell",
            maid.getNpcName(),
            prisoner.getName().getString()
        );
    }

    /**
     * Stuck detection: teleport maid to target if no progress.
     */
    private void tickStuckDetection(BlockPos target) {
        BlockPos currentPos = maid.blockPosition();
        if (
            lastProgressPos == null ||
            currentPos.distManhattan(lastProgressPos) >= 2
        ) {
            lastProgressPos = currentPos;
            stuckTicks = 0;
        } else {
            stuckTicks++;
        }
        if (stuckTicks >= STUCK_TELEPORT_TICKS) {
            TiedUpMod.LOGGER.info(
                "[MaidReturnGoal] {} stuck, teleporting to {}",
                maid.getNpcName(),
                target.toShortString()
            );
            maid.teleportTo(
                target.getX() + 0.5,
                target.getY() + 1,
                target.getZ() + 0.5
            );
            stuckTicks = 0;
            lastProgressPos = null;
        }
    }

    /**
     * Collect task items from prisoner and complete the return.
     * Called when maid arrives at the cell with the leashed prisoner.
     */
    private void collectAndReturn(ServerLevel level, ServerPlayer prisoner) {
        PrisonerManager manager = PrisonerManager.get(level);
        LaborRecord labor = manager.getLaborRecord(targetPrisonerId);
        LaborTask task = labor.getTask();
        UUID campId = manager.getRecord(targetPrisonerId).getCampId();

        // Collect task items
        if (task != null) {
            List<ItemStack> collected = ItemService.get().collectTaskItems(
                prisoner,
                task
            );
            List<ItemStack> tools = ItemService.get().reclaimEquipment(
                prisoner,
                task
            );

            // Store in camp chest
            if (campId != null) {
                BlockPos chestPos = ItemService.get().findCampChest(
                    level,
                    campId
                );
                if (chestPos != null) {
                    ItemService.get().storeInChest(level, chestPos, collected);
                    ItemService.get().storeInChest(level, chestPos, tools);
                }
            }

            // Credit earnings
            if (!labor.isTaskFailed()) {
                RansomRecord ransom = manager.getRansomRecord(targetPrisonerId);
                if (ransom != null) {
                    labor.addEarnings(task.getValue());
                    boolean paid = ransom.addPayment(task.getValue(), null);

                    String earningsFallback =
                        "Good work. " +
                        task.getValue() +
                        " emeralds have been deducted.";
                    String earningsText =
                        com.tiedup.remake.dialogue.DialogueBridge.getDialogue(
                            maid,
                            prisoner,
                            "maid.labor.earnings"
                        );
                    if (earningsText != null) {
                        earningsText = earningsText.replace(
                            "{value}",
                            String.valueOf(task.getValue())
                        );
                        String mn = maid.getNpcName();
                        if (mn == null || mn.isEmpty()) mn = "Maid";
                        prisoner.sendSystemMessage(
                            net.minecraft.network.chat.Component.literal(
                                "<" + mn + "> "
                            )
                                .withStyle(
                                    net.minecraft.network.chat.Style.EMPTY.withColor(
                                        net.minecraft.network.chat.TextColor.fromRgb(
                                            EntityMaid.MAID_NAME_COLOR
                                        )
                                    )
                                )
                                .append(
                                    net.minecraft.network.chat.Component.literal(
                                        earningsText
                                    ).withStyle(
                                        net.minecraft.ChatFormatting.WHITE
                                    )
                                )
                        );
                    } else {
                        maidSay(
                            prisoner,
                            "maid.labor.earnings",
                            earningsFallback
                        );
                    }
                }
            }
        }

        // Complete the return (teleport, restore bondage, state transition)
        completeReturn(level, prisoner);

        // Mark as completed so stop() doesn't try to undo anything
        leashed = false;
        targetPrisonerId = null;

        TiedUpMod.LOGGER.info(
            "[MaidReturnGoal] {} collected items and returned prisoner to cell",
            maid.getNpcName()
        );
    }

    /**
     * Complete the return - restore bondage and update state.
     * PrisonerService.returnToCell handles unleashing the prisoner.
     */
    private void completeReturn(ServerLevel level, ServerPlayer prisoner) {
        PrisonerManager manager = PrisonerManager.get(level);
        LaborRecord labor = manager.getLaborRecord(targetPrisonerId);
        PrisonerRecord record = manager.getRecord(targetPrisonerId);
        RansomRecord ransom = manager.getRansomRecord(targetPrisonerId);
        long currentTime = level.getGameTime();

        // Check if ransom is paid
        if (ransom != null && ransom.isPaid()) {
            // Free the prisoner!
            freePrisoner(level, prisoner, manager, currentTime);
            return;
        }

        // Teleport prisoner to cell spawn point (not core pos which is in the wall)
        UUID cellId2 = record.getCellId();
        if (cellId2 != null) {
            CellDataV2 cell2 = CellRegistryV2.get(level).getCell(cellId2);
            if (cell2 != null && cell2.getSpawnPoint() != null) {
                BlockPos spawn = cell2.getSpawnPoint();
                prisoner.teleportTo(
                    spawn.getX() + 0.5,
                    spawn.getY() + 0.1,
                    spawn.getZ() + 0.5
                );
            } else if (targetCellPos != null) {
                prisoner.teleportTo(
                    targetCellPos.getX() + 0.5,
                    targetCellPos.getY() + 1.0,
                    targetCellPos.getZ() + 0.5
                );
            }
        } else if (targetCellPos != null) {
            prisoner.teleportTo(
                targetCellPos.getX() + 0.5,
                targetCellPos.getY() + 1.0,
                targetCellPos.getZ() + 0.5
            );
        }

        // Restore bondage
        IBondageState cap = KidnappedHelper.getKidnappedState(prisoner);
        if (cap != null) {
            CompoundTag snapshot = labor.getBondageSnapshot();
            if (snapshot != null) {
                BondageService.get().restoreSnapshot(cap, snapshot);
            }
        }

        // Return to cell via PrisonerService (handles unleash + PrisonerManager + CellRegistry)
        UUID cellId = record.getCellId();
        if (cellId != null) {
            CellDataV2 cell = CellRegistryV2.get(level).getCell(cellId);
            if (cell != null) {
                com.tiedup.remake.prison.service.PrisonerService.get().returnToCell(
                    level,
                    prisoner,
                    null,
                    cell
                );
                // Start rest period
                labor.startRest(currentTime);
                maidSay(
                    prisoner,
                    "maid.labor.cell_return",
                    "Back to your cell. Rest before your next task."
                );
                TiedUpMod.LOGGER.info(
                    "[MaidReturnGoal] Returned {} to cell (state={})",
                    prisoner.getName().getString(),
                    record.getState()
                );
            } else {
                // Cell destroyed — reset to PENDING_RETURN, let PrisonerService timeout handle
                labor.completeTask(currentTime);
                TiedUpMod.LOGGER.warn(
                    "[MaidReturnGoal] Cell {} destroyed for {} - resetting to PENDING_RETURN",
                    cellId.toString().substring(0, 8),
                    prisoner.getName().getString()
                );
            }
        } else {
            // No cell ID — same fallback
            labor.completeTask(currentTime);
            TiedUpMod.LOGGER.warn(
                "[MaidReturnGoal] No cellId for {} - resetting to PENDING_RETURN",
                prisoner.getName().getString()
            );
        }
    }

    /**
     * Free a prisoner whose ransom is paid.
     */
    private void freePrisoner(
        ServerLevel level,
        ServerPlayer prisoner,
        PrisonerManager manager,
        long currentTime
    ) {
        UUID prisonerId = prisoner.getUUID();

        // 0. Despawn guard if present (might already be done in performLeash)
        LaborRecord labor = manager.getLaborRecord(prisonerId);
        despawnGuard(level, labor);

        // 1. Get cell ID before releasing (for removal from cell registry)
        PrisonerRecord record = manager.getRecord(prisonerId);
        UUID cellId = record.getCellId();

        // 2. Release with grace period (sets state to PROTECTED)
        manager.release(prisonerId, currentTime, GRACE_PERIOD_TICKS);

        // 3. Remove from cell registry (so guards don't track them)
        if (cellId != null) {
            CellRegistryV2 cellRegistry = CellRegistryV2.get(level);
            cellRegistry.releasePrisoner(cellId, prisonerId, level.getServer());
            TiedUpMod.LOGGER.debug(
                "[MaidReturnGoal] Removed {} from cell registry",
                prisoner.getName().getString()
            );
        }

        // 4. Clear collar from CollarRegistry FIRST (before removing the item)
        com.tiedup.remake.state.CollarRegistry collarRegistry =
            com.tiedup.remake.state.CollarRegistry.get(level);
        collarRegistry.unregisterWearer(prisonerId);

        // 5. Free kidnapped state and remove all restraints
        IBondageState cap = KidnappedHelper.getKidnappedState(prisoner);
        if (cap != null) {
            // Remove collar (force=true to bypass lock)
            net.minecraft.world.item.ItemStack collar = cap.getEquipment(
                BodyRegionV2.NECK
            );
            if (!collar.isEmpty()) {
                com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper.unequipFromRegion(
                    prisoner,
                    com.tiedup.remake.v2.BodyRegionV2.NECK,
                    true
                );
                TiedUpMod.LOGGER.debug(
                    "[MaidReturnGoal] Force-removed collar from {}",
                    prisoner.getName().getString()
                );
            }

            // Remove all restraints (binds, blindfold, gag)
            cap.untie(true); // Full untie including legs

            // Free from captivity state
            cap.free(false);
        }

        prisoner.sendSystemMessage(
            net.minecraft.network.chat.Component.translatable(
                "goal.tiedup.maid.debt_paid_free"
            ).withStyle(
                net.minecraft.ChatFormatting.GREEN,
                net.minecraft.ChatFormatting.BOLD
            )
        );

        TiedUpMod.LOGGER.info(
            "[MaidReturnGoal] Released {} - ransom paid, collar removed, freed from cell",
            prisoner.getName().getString()
        );
    }

    /**
     * Send a formatted maid speech message to a player.
     * Tries JSON dialogue first, falls back to provided message.
     */
    private void maidSay(
        ServerPlayer player,
        String dialogueId,
        String fallback
    ) {
        String text = com.tiedup.remake.dialogue.DialogueBridge.getDialogue(
            maid,
            player,
            dialogueId
        );
        if (text == null) {
            text = fallback;
        }
        MessageDispatcher.talkTo(maid, player, text);
    }

    /**
     * Despawn the guard entity assigned to this prisoner's labor record.
     */
    private void despawnGuard(ServerLevel level, LaborRecord labor) {
        java.util.UUID guardId = labor.getGuardId();
        if (guardId == null) return;

        net.minecraft.world.entity.Entity guardEntity = level.getEntity(
            guardId
        );
        if (guardEntity != null) {
            guardEntity.discard();
            TiedUpMod.LOGGER.debug(
                "[MaidReturnGoal] Despawned guard {}",
                guardId.toString().substring(0, 8)
            );
        } else {
            TiedUpMod.LOGGER.debug(
                "[MaidReturnGoal] Guard {} not found for despawn (may have died)",
                guardId.toString().substring(0, 8)
            );
        }

        labor.setGuardId(null);
    }

    @Override
    public boolean canContinueToUse() {
        if (targetPrisonerId == null) {
            return false;
        }
        if (maid.isFreed() || maid.isTiedUp()) {
            return false;
        }
        if (ticksActive >= MAX_DURATION_TICKS) {
            return false;
        }
        // Check prisoner still online
        if (maid.level() instanceof ServerLevel level) {
            ServerPlayer prisoner = level
                .getServer()
                .getPlayerList()
                .getPlayer(targetPrisonerId);
            if (prisoner == null || !prisoner.isAlive()) {
                return false;
            }
        }
        return true;
    }

    @Override
    public void stop() {
        // Release leash if still active (interrupted before completing return)
        if (
            leashed &&
            targetPrisonerId != null &&
            maid.level() instanceof ServerLevel level
        ) {
            ServerPlayer prisoner = level
                .getServer()
                .getPlayerList()
                .getPlayer(targetPrisonerId);
            if (prisoner != null) {
                IBondageState cap = KidnappedHelper.getKidnappedState(prisoner);
                if (cap != null && cap.isCaptive()) {
                    cap.free(false);
                }
            }
        }

        // If interrupted during WALKING_TO_CELL (phase=RETURNING), teleport prisoner to cell
        // instead of leaving them wandering for 2.5 min until PENDING_RETURN timeout kicks in
        if (
            targetPrisonerId != null &&
            maid.level() instanceof ServerLevel level
        ) {
            PrisonerManager manager = PrisonerManager.get(level);
            LaborRecord labor = manager.getLaborRecord(targetPrisonerId);
            if (
                labor != null &&
                labor.getPhase() == LaborRecord.WorkPhase.RETURNING
            ) {
                labor.completeTask(level.getGameTime()); // Back to PENDING_RETURN

                // Teleport prisoner to cell immediately if possible
                ServerPlayer strandedPrisoner = level
                    .getServer()
                    .getPlayerList()
                    .getPlayer(targetPrisonerId);
                if (strandedPrisoner != null && targetCellPos != null) {
                    strandedPrisoner.teleportTo(
                        targetCellPos.getX() + 0.5,
                        targetCellPos.getY(),
                        targetCellPos.getZ() + 0.5
                    );
                    TiedUpMod.LOGGER.warn(
                        "[MaidReturnGoal] Interrupted during escort of {} — teleported to cell",
                        targetPrisonerId.toString().substring(0, 8)
                    );
                } else {
                    TiedUpMod.LOGGER.warn(
                        "[MaidReturnGoal] Interrupted during escort of {} — PENDING_RETURN timeout will handle",
                        targetPrisonerId.toString().substring(0, 8)
                    );
                }
            }
        }

        maid.getNavigation().stop();
        maid.setMaidState(com.tiedup.remake.entities.ai.maid.MaidState.IDLE);

        targetPrisonerId = null;
        targetCellPos = null;
        targetCell = null;
        waypointNav = null;
        phase = null;
        navigationStarted = false;
        leashed = false;

        TiedUpMod.LOGGER.debug("[MaidReturnGoal] Stopped");
    }
}
