package com.tiedup.remake.entities.damsel.components;

import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.AbstractTiedUpNpc;
import com.tiedup.remake.state.ICaptor;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.util.RestraintEffectUtils;
import java.util.UUID;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;

/**
 * Captivity lifecycle for NPCs: capture, free, transfer, leash, captor restoration.
 *
 * <p>Extracted from DamselBondageManager (H9 split). Owns the captor reference
 * and pending UUID for restoration after world load.</p>
 */
public class NpcCaptivityManager {

    // FIELDS

    private final AbstractTiedUpNpc entity;
    private final IBondageHost host;
    private final NpcEquipmentManager equipment;

    /** Current captor (if captured) */
    private ICaptor captor;

    /** Pending captor UUID for restoration after world load */
    private UUID pendingCaptorUUID;

    // CONSTRUCTOR

    public NpcCaptivityManager(
        AbstractTiedUpNpc entity,
        IBondageHost host,
        NpcEquipmentManager equipment
    ) {
        this.entity = entity;
        this.host = host;
        this.equipment = equipment;
    }

    // CAPTIVITY STATE

    public boolean isCaptive() {
        return entity.isLeashed();
    }

    public boolean isEnslavable() {
        if (entity.isLeashed()) return false;
        return equipment.isTiedUp();
    }

    public ICaptor getCaptor() {
        return captor;
    }

    /**
     * Clear the captor reference without triggering free() or untie().
     * Used when player detaches leash -- only clears the internal reference.
     */
    public void clearCaptor() {
        this.captor = null;
    }

    // CAPTURE LIFECYCLE

    public boolean getCapturedBy(ICaptor newCaptor) {
        if (newCaptor == null || !isEnslavable()) {
            return false;
        }

        if (!newCaptor.canCapture(this.asFacadeKidnapped())) {
            return false;
        }

        // Use vanilla leash mechanic
        Entity captorEntity = newCaptor.getEntity();
        if (captorEntity != null) {
            entity.setLeashedTo(captorEntity, true);
            this.captor = newCaptor;
            newCaptor.addCaptive(entity);

            TiedUpMod.LOGGER.info(
                "[EntityDamsel] {} captured by {}",
                host.getNpcName(),
                captorEntity.getName().getString()
            );
            return true;
        }

        return false;
    }

    /**
     * Force capture for managed camp operations (dogwalk, extract).
     * Bypasses canCapture() PrisonerManager state check since the
     * caller is responsible for managing state transitions.
     */
    public boolean forceCapturedBy(ICaptor newCaptor) {
        if (newCaptor == null || !isEnslavable()) {
            return false;
        }
        // Skip canCapture() - caller manages PrisonerManager state
        Entity captorEntity = newCaptor.getEntity();
        if (captorEntity != null) {
            entity.setLeashedTo(captorEntity, true);
            this.captor = newCaptor;
            newCaptor.addCaptive(entity);
            TiedUpMod.LOGGER.info(
                "[EntityDamsel] {} force-captured by {} (managed op)",
                host.getNpcName(),
                captorEntity.getName().getString()
            );
            return true;
        }
        return false;
    }

    public void free() {
        free(true);
    }

    public void free(boolean transportState) {
        if (!isCaptive()) return;

        if (transportState) {
            TiedUpMod.LOGGER.info(
                "[EntityDamsel] {} freed from captivity",
                host.getNpcName()
            );

            // Broadcast freed dialogue
            if (!entity.level().isClientSide()) {
                host.talkToPlayersInRadius(
                    com.tiedup.remake.dialogue.EntityDialogueManager.DialogueCategory.DAMSEL_FREED,
                    SettingsAccessor.getDialogueRadius()
                );
            }
        } else {
            TiedUpMod.LOGGER.debug(
                "[EntityDamsel] {} transferred (leash dropped)",
                host.getNpcName()
            );
        }

        // Drop leash (only drop item on true freedom, not internal transfers like imprisonment)
        entity.dropLeash(true, transportState);

        // Clear captor
        if (captor != null) {
            captor.removeCaptive(entity, transportState);
            captor = null;
        }
    }

    public void transferCaptivityTo(ICaptor newCaptor) {
        if (!isCaptive()) return;

        ICaptor currentCaptor = getCaptor();
        if (currentCaptor == null) return;

        if (!currentCaptor.allowCaptiveTransfer()) {
            TiedUpMod.LOGGER.warn(
                "[EntityDamsel] {} transfer blocked by current captor",
                host.getNpcName()
            );
            return;
        }

        // Free from current captor (keep transport entity)
        free(false);

        // Capture by new captor
        getCapturedBy(newCaptor);

        TiedUpMod.LOGGER.info(
            "[EntityDamsel] {} transferred to new captor",
            host.getNpcName()
        );
    }

    // POLE / LEASH

    public boolean isTiedToPole() {
        Entity leashHolder = entity.getLeashHolder();
        return (
            leashHolder instanceof
                net.minecraft.world.entity.decoration.LeashFenceKnotEntity
        );
    }

    public boolean tieToClosestPole(int searchRadius) {
        return RestraintEffectUtils.tieToClosestPole(entity, searchRadius);
    }

    public boolean canBeKidnappedByEvents() {
        return !isCaptive() && !equipment.hasCollar();
    }

    // CAPTOR RESTORATION

    /**
     * Attempt to restore captor from pending UUID.
     * Call this from EntityDamsel.tick() until successful.
     */
    public void restoreCaptorFromUUID() {
        if (pendingCaptorUUID == null) return;

        // Search for entity with matching UUID
        for (Entity searchEntity : entity
            .level()
            .getEntities(entity, entity.getBoundingBox().inflate(64))) {
            if (searchEntity.getUUID().equals(pendingCaptorUUID)) {
                if (searchEntity instanceof ICaptor kidnapper) {
                    captor = kidnapper;
                    kidnapper.addCaptive(entity);
                    TiedUpMod.LOGGER.info(
                        "[EntityDamsel] {} restored captor relationship with {}",
                        host.getNpcName(),
                        searchEntity.getName().getString()
                    );
                }
                pendingCaptorUUID = null;
                return;
            }
        }

        // Also check players (PlayerBindState.getCaptorManager() is ICaptor)
        for (net.minecraft.world.entity.player.Player player : entity
            .level()
            .players()) {
            if (player.getUUID().equals(pendingCaptorUUID)) {
                PlayerBindState bindState = PlayerBindState.getInstance(player);
                if (bindState != null) {
                    ICaptor kidnapper = bindState.getCaptorManager();
                    if (kidnapper != null) {
                        captor = kidnapper;
                        kidnapper.addCaptive(entity);
                        TiedUpMod.LOGGER.info(
                            "[EntityDamsel] {} restored captor relationship with player {}",
                            host.getNpcName(),
                            player.getName().getString()
                        );
                    }
                }
                pendingCaptorUUID = null;
                return;
            }
        }
    }

    // PERSISTENCE

    /**
     * Save captivity-related state to NBT.
     */
    public void saveCaptivityToTag(CompoundTag tag) {
        if (captor != null && captor.getEntity() != null) {
            tag.putUUID("CaptorUUID", captor.getEntity().getUUID());
        }
    }

    /**
     * Load captivity-related state from NBT.
     */
    public void loadCaptivityFromTag(CompoundTag tag) {
        if (tag.contains("CaptorUUID")) {
            pendingCaptorUUID = tag.getUUID("CaptorUUID");
        } else if (tag.contains("MasterUUID")) {
            // Legacy support
            pendingCaptorUUID = tag.getUUID("MasterUUID");
        }
    }

    // INTERNAL

    /**
     * Get the facade IRestrainable reference for canCapture() calls.
     * This is the entity itself (AbstractTiedUpNpc implements IRestrainable via delegation).
     */
    private com.tiedup.remake.state.IRestrainable asFacadeKidnapped() {
        return (com.tiedup.remake.state.IRestrainable) entity;
    }
}
