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

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityMaid;
import com.tiedup.remake.state.IRestrainable;
import com.tiedup.remake.util.KidnappedHelper;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.EnumSet;
import java.util.UUID;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.player.Player;

/**
 * AI Goal for EntityMaid to deliver a captive to a buyer.
 *
 * Behavior:
 * - Active when state is DELIVERING
 * - Walks towards buyer (3-block distance)
 * - Releases captive upon arrival
 */
public class MaidDeliverCaptiveGoal extends Goal {

    private final EntityMaid maid;

    /** Distance at which delivery is complete */
    private static final double DELIVERY_DISTANCE = 3.0;

    /** Maximum ticks before giving up */
    private static final int MAX_DELIVERY_TICKS = 1200; // 60 seconds

    /** Cached buyer entity */
    private Player buyerEntity;

    /** Cached captive */
    private LivingEntity captiveEntity;

    /** Ticks spent delivering */
    private int deliveryTicks = 0;

    /** Consecutive path failures before forced teleport */
    private static final int PATH_FAIL_THRESHOLD = 3;

    /** Counter for consecutive path failures */
    private int pathFailCounter = 0;

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

    @Override
    public boolean canUse() {
        // Must be in DELIVERING state
        if (maid.getMaidState() != MaidState.DELIVERING) {
            return false;
        }

        // Must not be tied up
        if (maid.isTiedUp()) {
            return false;
        }

        // Must have target captive and buyer
        UUID captiveUUID = maid.getTargetCaptiveUUID();
        UUID buyerUUID = maid.getTargetBuyerUUID();

        if (captiveUUID == null || buyerUUID == null) {
            return false;
        }

        // Must be on server
        if (!(maid.level() instanceof ServerLevel serverLevel)) {
            return false;
        }

        // Find buyer
        var buyer = serverLevel.getEntity(buyerUUID);
        if (!(buyer instanceof Player player) || !player.isAlive()) {
            // Buyer logged off or died - cancel delivery
            maid.completeTask();
            return false;
        }
        this.buyerEntity = player;

        // Find captive
        var captive = serverLevel.getEntity(captiveUUID);
        if (!(captive instanceof LivingEntity living) || !living.isAlive()) {
            // Captive died - cancel delivery
            maid.completeTask();
            return false;
        }
        this.captiveEntity = living;

        return true;
    }

    @Override
    public boolean canContinueToUse() {
        if (maid.getMaidState() != MaidState.DELIVERING) {
            return false;
        }

        if (maid.isTiedUp()) {
            return false;
        }

        if (buyerEntity == null || !buyerEntity.isAlive()) {
            return false;
        }

        if (captiveEntity == null || !captiveEntity.isAlive()) {
            return false;
        }

        // Timeout check
        if (deliveryTicks > MAX_DELIVERY_TICKS) {
            TiedUpMod.LOGGER.warn(
                "[MaidDeliverCaptiveGoal] {} delivery timed out",
                maid.getNpcName()
            );
            maid.completeTask();
            return false;
        }

        return true;
    }

    @Override
    public void start() {
        deliveryTicks = 0;
        pathFailCounter = 0;

        TiedUpMod.LOGGER.info(
            "[MaidDeliverCaptiveGoal] {} starting delivery to {}",
            maid.getNpcName(),
            buyerEntity != null ? buyerEntity.getName().getString() : "unknown"
        );
    }

    @Override
    public void stop() {
        buyerEntity = null;
        captiveEntity = null;
        deliveryTicks = 0;
        pathFailCounter = 0;
        maid.getNavigation().stop();
        maid.setMaidState(MaidState.IDLE);
    }

    @Override
    public void tick() {
        if (buyerEntity == null || captiveEntity == null) {
            return;
        }

        deliveryTicks++;

        // Check distance to buyer
        double distSq = maid.distanceToSqr(buyerEntity);

        if (distSq < DELIVERY_DISTANCE * DELIVERY_DISTANCE) {
            // Close enough - complete delivery
            completeDelivery();
        } else {
            // Move towards buyer
            if (deliveryTicks % 10 == 0) {
                boolean pathFound = maid
                    .getNavigation()
                    .moveTo(buyerEntity, 1.0);

                // Track path failures
                if (!pathFound) {
                    pathFailCounter++;
                    TiedUpMod.LOGGER.debug(
                        "[MaidDeliverCaptiveGoal] {} path failed ({}/{})",
                        maid.getNpcName(),
                        pathFailCounter,
                        PATH_FAIL_THRESHOLD
                    );

                    // Teleport if path fails too many times
                    if (pathFailCounter >= PATH_FAIL_THRESHOLD) {
                        TiedUpMod.LOGGER.info(
                            "[MaidDeliverCaptiveGoal] {} can't find path, teleporting to buyer",
                            maid.getNpcName()
                        );
                        maid.teleportTo(
                            buyerEntity.getX(),
                            buyerEntity.getY(),
                            buyerEntity.getZ()
                        );
                        pathFailCounter = 0;
                        return;
                    }
                } else {
                    pathFailCounter = 0;
                }
            }

            // Only look at buyer if we have an active path
            if (!maid.getNavigation().isDone()) {
                maid.getLookControl().setLookAt(buyerEntity, 30.0F, 30.0F);
            }
        }
    }

    /**
     * Complete the delivery - transfer captive to buyer with leash attached.
     * Uses PrisonerService.transferCaptive() for atomic leash transfer.
     */
    private void completeDelivery() {
        if (captiveEntity == null || buyerEntity == null) {
            return;
        }

        // Get captive's kidnapped state
        IRestrainable kidnappedState = KidnappedHelper.getKidnappedState(
            captiveEntity
        );

        if (kidnappedState != null) {
            // 1. Cancel sale state (they've been sold)
            kidnappedState.cancelSale();

            // 2. Transfer collar ownership to buyer
            net.minecraft.world.item.ItemStack collar =
                kidnappedState.getEquipment(BodyRegionV2.NECK);
            if (
                !collar.isEmpty() &&
                com.tiedup.remake.v2.bondage.CollarHelper.isCollar(collar)
            ) {
                for (java.util.UUID ownerId : new java.util.ArrayList<>(
                    com.tiedup.remake.v2.bondage.CollarHelper.getOwners(collar)
                )) {
                    com.tiedup.remake.v2.bondage.CollarHelper.removeOwner(collar, ownerId);
                }
                com.tiedup.remake.v2.bondage.CollarHelper.addOwner(
                    collar,
                    buyerEntity.getUUID(),
                    buyerEntity.getName().getString()
                );
                if (collar.getItem() instanceof com.tiedup.remake.items.base.ILockable lockable) {
                    lockable.setLocked(collar, false);
                }
                kidnappedState.equip(BodyRegionV2.NECK, collar);

                if (
                    maid.level() instanceof
                        net.minecraft.server.level.ServerLevel serverLevel
                ) {
                    com.tiedup.remake.state.CollarRegistry collarRegistry =
                        com.tiedup.remake.state.CollarRegistry.get(serverLevel);
                    if (collarRegistry != null) {
                        collarRegistry.unregisterWearer(
                            captiveEntity.getUUID()
                        );
                        collarRegistry.registerCollar(
                            captiveEntity.getUUID(),
                            buyerEntity.getUUID()
                        );
                    }
                }

                if (
                    captiveEntity instanceof
                        net.minecraft.server.level.ServerPlayer captivePlayer
                ) {
                    com.tiedup.remake.network.sync.SyncManager.syncBindState(
                        captivePlayer
                    );
                }

                TiedUpMod.LOGGER.info(
                    "[MaidDeliverCaptiveGoal] Transferred collar ownership to {}",
                    buyerEntity.getName().getString()
                );
            }

            // 3. Transfer captive from maid to buyer via PrisonerService
            com.tiedup.remake.state.PlayerBindState buyerState =
                com.tiedup.remake.state.PlayerBindState.getInstance(
                    buyerEntity
                );
            boolean transferred = false;
            if (
                buyerState != null &&
                maid.level() instanceof
                    net.minecraft.server.level.ServerLevel serverLevel
            ) {
                com.tiedup.remake.state.PlayerCaptorManager captorManager =
                    buyerState.getCaptorManager();
                if (captorManager != null) {
                    transferred =
                        com.tiedup.remake.prison.service.PrisonerService.get().transferCaptive(
                            serverLevel,
                            captiveEntity,
                            (com.tiedup.remake.state.ICaptor) maid,
                            captorManager
                        );
                }
            }

            // 4. Release from PrisonerManager (bought = fully released from camp)
            if (
                maid.level() instanceof
                    net.minecraft.server.level.ServerLevel serverLevel
            ) {
                com.tiedup.remake.prison.PrisonerManager manager =
                    com.tiedup.remake.prison.PrisonerManager.get(serverLevel);
                manager.release(
                    captiveEntity.getUUID(),
                    serverLevel.getGameTime()
                );
            }

            if (transferred) {
                // Give buyer a Lead item so they can manage the leash
                buyerEntity
                    .getInventory()
                    .add(
                        new net.minecraft.world.item.ItemStack(
                            net.minecraft.world.item.Items.LEAD,
                            1
                        )
                    );

                TiedUpMod.LOGGER.info(
                    "[MaidDeliverCaptiveGoal] Leash attached to buyer {}",
                    buyerEntity.getName().getString()
                );
                buyerEntity.sendSystemMessage(
                    net.minecraft.network.chat.Component.translatable(
                        "goal.tiedup.maid_deliver.on_leash",
                        captiveEntity.getName().getString()
                    ).withStyle(net.minecraft.ChatFormatting.GREEN)
                );
            } else {
                TiedUpMod.LOGGER.warn(
                    "[MaidDeliverCaptiveGoal] Transfer to buyer failed, freeing captive"
                );
                kidnappedState.free(true);
                buyerEntity.sendSystemMessage(
                    net.minecraft.network.chat.Component.translatable(
                        "goal.tiedup.maid_deliver.delivered",
                        captiveEntity.getName().getString()
                    ).withStyle(net.minecraft.ChatFormatting.GREEN)
                );
            }

            TiedUpMod.LOGGER.info(
                "[MaidDeliverCaptiveGoal] {} delivered {} to {}",
                maid.getNpcName(),
                captiveEntity.getName().getString(),
                buyerEntity.getName().getString()
            );
        }

        // Complete task
        maid.completeTask();
    }
}
