package com.tiedup.remake.entities;

import com.tiedup.remake.cells.CampMaidManager;
import com.tiedup.remake.cells.CampOwnership;
import com.tiedup.remake.cells.CellRegistryV2;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.dialogue.SpeakerType;
import com.tiedup.remake.entities.ai.maid.MaidCollectRansomGoal;
import com.tiedup.remake.entities.ai.maid.MaidDefendTraderGoal;
import com.tiedup.remake.entities.ai.maid.MaidDeliverCaptiveGoal;
import com.tiedup.remake.entities.ai.maid.MaidFetchCaptiveGoal;
import com.tiedup.remake.entities.ai.maid.MaidFollowTraderGoal;
import com.tiedup.remake.entities.ai.maid.MaidState;
import com.tiedup.remake.entities.ai.maid.goals.MaidAssignTaskGoal;
import com.tiedup.remake.entities.ai.maid.goals.MaidExtractGoal;
import com.tiedup.remake.entities.ai.maid.goals.MaidIdleGoal;
// Prison system v2 goals
import com.tiedup.remake.entities.ai.maid.goals.MaidInitPrisonerGoal;
import com.tiedup.remake.entities.ai.maid.goals.MaidReturnGoal;
import com.tiedup.remake.entities.maid.components.MaidPrisonInteraction;
import com.tiedup.remake.entities.maid.components.MaidTraderLink;
import com.tiedup.remake.entities.skins.Gender;
import com.tiedup.remake.entities.skins.MaidSkinManager;
import com.tiedup.remake.personality.PersonalityType;
import com.tiedup.remake.prison.LaborRecord;
import com.tiedup.remake.prison.PrisonerManager;
import com.tiedup.remake.prison.PrisonerRecord;
import com.tiedup.remake.state.IRestrainable;
import com.tiedup.remake.util.teleport.Position;
import com.tiedup.remake.util.teleport.TeleportHelper;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nullable;
import net.minecraft.ChatFormatting;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.*;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;

/**
 * EntityMaid - Servant of the SlaveTrader who executes orders.
 *
 * Slave Trader & Maid System
 *
 * Characteristics:
 * - Highest stats in the mod (ultra fast capture)
 * - Bound to a SlaveTrader (masterUUID)
 * - Executes trader's orders (deliver, collect, fetch)
 * - Passive unless trader is threatened
 * - When trader dies, becomes neutral and capturable
 *
 * Skin: Maid outfit
 */
public class EntityMaid extends EntityKidnapperElite {

    // CONSTANTS

    public static final double MAID_MAX_HEALTH = 60.0D;
    public static final double MAID_MOVEMENT_SPEED = 0.28D; // Reduced from 0.40 - more natural pace
    public static final double MAID_KNOCKBACK_RESISTANCE = 0.8D;
    public static final double MAID_FOLLOW_RANGE = 50.0D;
    public static final double MAID_ATTACK_DAMAGE = 12.0D;
    public static final int MAID_CAPTURE_TIME_TICKS = 5; // Ultra fast
    public static final int MAID_NAME_COLOR = 0xFF69B4; // Hot Pink

    // DATA SYNC

    private static final EntityDataAccessor<String> DATA_MAID_STATE =
        SynchedEntityData.defineId(
            EntityMaid.class,
            EntityDataSerializers.STRING
        );

    // STATE

    /** Trader link component — manages master trader lookup, caching, and linking */
    private final MaidTraderLink traderLink;

    /** Prison interaction component — prisoner check-in, extraction, struggle detection */
    private final MaidPrisonInteraction prisonInteraction;

    /** Current behavioral state */
    private MaidState currentState = MaidState.IDLE;

    /** UUID of captive to deliver/fetch */
    @Nullable
    private UUID targetCaptiveUUID;

    /** UUID of buyer destination */
    @Nullable
    private UUID targetBuyerUUID;

    /** Position to collect items from */
    @Nullable
    private BlockPos collectTarget;

    // CONSTRUCTOR

    public EntityMaid(EntityType<? extends EntityMaid> type, Level level) {
        super(type, level);
        this.traderLink = new MaidTraderLink(this);
        this.prisonInteraction = new MaidPrisonInteraction(this);
        // Configure navigation for better pathfinding in structures
        if (
            this.getNavigation() instanceof
                net.minecraft.world.entity.ai.navigation.GroundPathNavigation groundNav
        ) {
            groundNav.setCanOpenDoors(true);
            groundNav.setCanPassDoors(true);
        }
    }

    // ATTRIBUTES

    public static AttributeSupplier.Builder createAttributes() {
        return Mob.createMobAttributes()
            .add(Attributes.MAX_HEALTH, MAID_MAX_HEALTH)
            .add(Attributes.MOVEMENT_SPEED, MAID_MOVEMENT_SPEED)
            .add(Attributes.KNOCKBACK_RESISTANCE, MAID_KNOCKBACK_RESISTANCE)
            .add(Attributes.FOLLOW_RANGE, MAID_FOLLOW_RANGE)
            .add(Attributes.ATTACK_DAMAGE, MAID_ATTACK_DAMAGE);
    }

    // DATA SYNC

    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.define(DATA_MAID_STATE, MaidState.IDLE.name());
    }

    // AI GOALS

    @Override
    protected void registerGoals() {
        // Priority 0: Always swim
        this.goalSelector.addGoal(0, new FloatGoal(this));

        // Priority 1: Defend trader (highest combat priority)
        this.goalSelector.addGoal(1, new MaidDefendTraderGoal(this));

        // Priority 2: Deliver captive to buyer
        this.goalSelector.addGoal(2, new MaidDeliverCaptiveGoal(this));

        // Priority 2: Extract prisoner from cell for labor
        this.goalSelector.addGoal(2, new MaidExtractGoal(this));

        // Priority 2: Return prisoner to cell after labor
        this.goalSelector.addGoal(2, new MaidReturnGoal(this));

        // Priority 3: Collect ransom/items
        this.goalSelector.addGoal(3, new MaidCollectRansomGoal(this));

        // Priority 3: Initialize new prisoners
        this.goalSelector.addGoal(3, new MaidInitPrisonerGoal(this));

        // Priority 3: Assign tasks to idle prisoners
        this.goalSelector.addGoal(3, new MaidAssignTaskGoal(this));

        // Priority 4: Fetch captive from cell (for sale)
        this.goalSelector.addGoal(4, new MaidFetchCaptiveGoal(this));

        // Priority 5: Follow trader
        this.goalSelector.addGoal(5, new MaidFollowTraderGoal(this));

        // Priority 6: Fight back if attacked
        this.goalSelector.addGoal(
            6,
            new com.tiedup.remake.entities.ai.kidnapper.KidnapperFightBackGoal(
                this
            )
        );

        // Priority 7: Melee attack
        this.goalSelector.addGoal(7, new MeleeAttackGoal(this, 1.2D, false));

        // Priority 8: Idle behavior (monitor workers, patrol)
        this.goalSelector.addGoal(8, new MaidIdleGoal(this));

        // These were non-functional before (Maids have no PersonalityState).
        // Proper fix: Create MaidCommandGoals that use collar owner instead.
        // DamselAIController.registerCommandGoals(this.goalSelector, this, 9);

        // Priority 10: Look at players
        this.goalSelector.addGoal(
            10,
            new LookAtPlayerGoal(this, Player.class, 8.0F)
        );

        // Priority 11: Random look around
        this.goalSelector.addGoal(11, new RandomLookAroundGoal(this));

        // Priority 12: Wander when idle
        this.goalSelector.addGoal(
            12,
            new WaterAvoidingRandomStrollGoal(this, 0.8D)
        );
    }

    // STATE MANAGEMENT

    public MaidState getMaidState() {
        return currentState;
    }

    public void setMaidState(MaidState state) {
        if (this.currentState != state) {
            TiedUpMod.LOGGER.debug(
                "[EntityMaid] {} state change: {} -> {}",
                this.getNpcName(),
                this.currentState,
                state
            );
            this.currentState = state;
            this.entityData.set(DATA_MAID_STATE, state.name());
        }
    }

    /**
     * Check if the maid is in freed state (trader dead).
     */
    public boolean isFreed() {
        return currentState == MaidState.FREE;
    }

    // MASTER TRADER (facades to MaidTraderLink)

    @Nullable
    public UUID getMasterTraderUUID() {
        return traderLink.getMasterTraderUUID();
    }

    public void setMasterTraderUUID(@Nullable UUID masterTraderUUID) {
        traderLink.setMasterTraderUUID(masterTraderUUID);
    }

    /**
     * Get the master trader entity.
     * Delegates to MaidTraderLink for multi-level lookup.
     */
    @Nullable
    public EntitySlaveTrader getMasterTrader() {
        return traderLink.getMasterTrader();
    }

    /**
     * Get the camp UUID this maid belongs to.
     * Delegates to MaidTraderLink.
     */
    @Nullable
    public UUID getCampUUID() {
        return traderLink.getCampUUID();
    }

    /**
     * Get the trader link component.
     * Exposed for direct component access when needed (e.g., testing).
     */
    public MaidTraderLink getTraderLink() {
        return traderLink;
    }

    // STUCK DETECTION

    /** Last recorded position for stuck detection */
    private transient Vec3 stuckCheckPos = Vec3.ZERO;

    /** Tick counter for stuck detection */
    private transient int stuckTimer = 0;

    /** Interval for stuck position checks (1 second) */
    private static final int STUCK_CHECK_INTERVAL = 20;

    /** Threshold for stuck detection (30 seconds) */
    private static final int STUCK_THRESHOLD = 600;

    /** Minimum distance to consider moved (blocks) */
    private static final double STUCK_MOVE_THRESHOLD = 2.0;

    // TICK

    @Override
    public void tick() {
        super.tick();

        // Server-side only: periodic link establishment if no master trader
        if (
            !this.level().isClientSide &&
            this.level() instanceof ServerLevel serverLevel
        ) {
            traderLink.tickLinkEstablishment(serverLevel);
            tickStuckDetection(serverLevel);

            // Check if captured and removed from camp (every second)
            if (this.tickCount % 20 == 0) {
                checkIfCapturedAndRemoved(serverLevel);
            }
        }
    }

    /**
     * Check if the maid is stuck and teleport home if needed.
     */
    private void tickStuckDetection(ServerLevel serverLevel) {
        // Only check every second
        if (tickCount % STUCK_CHECK_INTERVAL != 0) {
            return;
        }

        // Only check if actively navigating and not tied up
        if (!isNavigating() || isTiedUp() || isFreed()) {
            stuckTimer = 0;
            return;
        }

        Vec3 currentPos = position();
        double distMoved = currentPos.distanceTo(stuckCheckPos);

        if (distMoved < STUCK_MOVE_THRESHOLD) {
            stuckTimer += STUCK_CHECK_INTERVAL;

            if (stuckTimer >= STUCK_THRESHOLD) {
                teleportToHome(serverLevel);
                stuckTimer = 0;
            }
        } else {
            stuckTimer = 0;
        }
        stuckCheckPos = currentPos;
    }

    /**
     * Check if the maid is actively navigating.
     */
    private boolean isNavigating() {
        return !getNavigation().isDone();
    }

    /**
     * Teleport the maid back to her home camp.
     */
    private void teleportToHome(ServerLevel serverLevel) {
        EntitySlaveTrader trader = getMasterTrader();
        if (trader != null) {
            BlockPos homePos = trader.blockPosition();
            TeleportHelper.teleportEntity(
                this,
                new Position(homePos, serverLevel.dimension())
            );
            getNavigation().stop();
            setMaidState(MaidState.IDLE);
            TiedUpMod.LOGGER.info(
                "[EntityMaid] {} was stuck, teleported home",
                getNpcName()
            );
        }
    }

    /**
     * Called when the master trader dies.
     * Maid becomes neutral and capturable.
     * Prisoners are reassigned in CampOwnership (maidId cleared but campId preserved).
     */
    public void onTraderDeath() {
        TiedUpMod.LOGGER.info(
            "[EntityMaid] {} trader died, becoming free",
            this.getNpcName()
        );

        // Reassign prisoners (clear maid reference)
        if (this.level() instanceof ServerLevel serverLevel) {
            CampMaidManager.reassignPrisonersFromMaid(
                this.getUUID(),
                null,
                serverLevel
            );
        }

        traderLink.clearTraderUUID();
        this.setMaidState(MaidState.FREE);
        this.setTarget(null);

        // Clear any current tasks
        this.targetCaptiveUUID = null;
        this.targetBuyerUUID = null;
        this.collectTarget = null;
    }

    /**
     * Handle maid death.
     * Registers death time in CampOwnership for respawn timer.
     * Prisoners are paused but not freed (camp is still alive).
     */
    @Override
    public void die(
        net.minecraft.world.damagesource.DamageSource damageSource
    ) {
        if (
            !this.level().isClientSide &&
            this.level() instanceof ServerLevel serverLevel
        ) {
            // Get camp UUID before death
            UUID campId = getCampUUID();

            if (campId != null && !isFreed()) {
                // Mark maid as dead - prisoners are paused, respawn in 5 minutes
                CampMaidManager.markMaidDead(
                    campId,
                    serverLevel.getGameTime(),
                    serverLevel
                );

                // Release any currently captured prisoner (leashed)
                if (this.hasCaptives()) {
                    IRestrainable captive = this.getCaptive();
                    if (captive != null) {
                        captive.free(false);
                    }
                }

                // Notify nearby prisoners using PrisonerManager
                PrisonerManager manager = PrisonerManager.get(serverLevel);
                for (UUID prisonerId : manager.getPrisonersInCamp(campId)) {
                    ServerPlayer player = serverLevel
                        .getServer()
                        .getPlayerList()
                        .getPlayer(prisonerId);
                    if (
                        player != null &&
                        player.position().distanceTo(this.position()) <= 50
                    ) {
                        player.sendSystemMessage(
                            net.minecraft.network.chat.Component.translatable(
                                "entity.tiedup.maid.died_work_paused"
                            ).withStyle(net.minecraft.ChatFormatting.GOLD)
                        );
                    }
                }

                TiedUpMod.LOGGER.info(
                    "[EntityMaid] {} died, camp {} awaiting maid respawn",
                    this.getNpcName(),
                    campId.toString().substring(0, 8)
                );
            }
        }

        super.die(damageSource);
    }

    @Override
    public void remove(RemovalReason reason) {
        // MEDIUM FIX: Handle cleanup for camp system if removed without dying
        if (
            !this.level().isClientSide &&
            reason == RemovalReason.DISCARDED &&
            !this.isDeadOrDying()
        ) {
            if (
                this.level() instanceof
                    net.minecraft.server.level.ServerLevel serverLevel
            ) {
                UUID campId = getCampUUID();
                if (campId != null) {
                    // Mark as dead so a replacement can be scheduled
                    CampMaidManager.markMaidDead(
                        campId,
                        serverLevel.getGameTime(),
                        serverLevel
                    );
                    TiedUpMod.LOGGER.info(
                        "[EntityMaid] {} removed without dying, notifying camp {}",
                        getNpcName(),
                        campId.toString().substring(0, 8)
                    );
                }
            }
        }

        // Standard kidnapper cleanup (captives)
        super.remove(reason);
    }

    // CAPTURE DETECTION

    /**
     * Check if maid has been captured and removed from camp.
     * If captured and taken far from camp (>100 blocks), the maid is marked as "dead"
     * and a replacement will spawn after 5 minutes.
     */
    private void checkIfCapturedAndRemoved(ServerLevel level) {
        // Must be tied up
        if (!isTiedUp()) return;

        // Must have master trader (not freed)
        if (isFreed() || getMasterTraderUUID() == null) return;

        // Must have a camp
        UUID campId = getCampUUID();
        if (campId == null) return;

        CampOwnership ownership = CampOwnership.get(level);
        CampOwnership.CampData camp = ownership.getCamp(campId);
        if (camp == null || camp.getCenter() == null) return;

        // Check distance from camp center
        BlockPos campCenter = camp.getCenter();
        double distanceSq = this.distanceToSqr(
            campCenter.getX(),
            campCenter.getY(),
            campCenter.getZ()
        );

        // If > 100 blocks away → maid "dead" for camp
        double CAPTURE_DISTANCE_THRESHOLD = 100.0;
        if (
            distanceSq > CAPTURE_DISTANCE_THRESHOLD * CAPTURE_DISTANCE_THRESHOLD
        ) {
            TiedUpMod.LOGGER.warn(
                "[EntityMaid] {} captured and removed {} blocks from camp {} - registering death",
                this.getNpcName(),
                (int) Math.sqrt(distanceSq),
                campId.toString().substring(0, 8)
            );

            // Register death (triggers 5-minute replacement timer)
            CampMaidManager.markMaidDead(campId, level.getGameTime(), level);

            // Detach from camp (become neutral)
            onCapturedAndRemoved();
        }
    }

    /**
     * Called when maid is captured and removed from camp.
     * Maid becomes neutral/freed and replacement timer starts.
     */
    private void onCapturedAndRemoved() {
        TiedUpMod.LOGGER.info(
            "[EntityMaid] {} captured - becoming neutral, replacement will spawn in 5 minutes",
            this.getNpcName()
        );

        // Clear trader link
        traderLink.clearTraderUUID();

        // Become free/neutral
        this.setMaidState(MaidState.FREE);

        // Clear tasks
        this.targetCaptiveUUID = null;
        this.targetBuyerUUID = null;
        this.collectTarget = null;

        // Clear target
        this.setTarget(null);
    }

    // ORDER HANDLING

    /**
     * Start delivering a captive to a buyer.
     */
    public void startDeliverCaptive(IRestrainable captive, Player buyer) {
        if (currentState.isBusy()) {
            TiedUpMod.LOGGER.warn(
                "[EntityMaid] {} cannot deliver - busy with {}",
                this.getNpcName(),
                currentState
            );
            return;
        }

        this.targetCaptiveUUID = captive.getKidnappedUniqueId();
        this.targetBuyerUUID = buyer.getUUID();
        setMaidState(MaidState.DELIVERING);

        TiedUpMod.LOGGER.info(
            "[EntityMaid] {} starting delivery of {} to {}",
            this.getNpcName(),
            captive.getKidnappedName(),
            buyer.getName().getString()
        );
    }

    /**
     * Start collecting items from a location.
     */
    public void startCollectItems(BlockPos target) {
        if (currentState.isBusy()) {
            TiedUpMod.LOGGER.warn(
                "[EntityMaid] {} cannot collect - busy with {}",
                this.getNpcName(),
                currentState
            );
            return;
        }

        this.collectTarget = target;
        setMaidState(MaidState.COLLECTING);

        TiedUpMod.LOGGER.info(
            "[EntityMaid] {} starting collection at {}",
            this.getNpcName(),
            target.toShortString()
        );
    }

    /**
     * Start fetching a captive from their cell.
     */
    public void startFetchCaptive(UUID captiveUUID) {
        if (currentState.isBusy()) {
            TiedUpMod.LOGGER.warn(
                "[EntityMaid] {} cannot fetch - busy with {}",
                this.getNpcName(),
                currentState
            );
            return;
        }

        this.targetCaptiveUUID = captiveUUID;
        setMaidState(MaidState.FETCHING);

        TiedUpMod.LOGGER.info(
            "[EntityMaid] {} starting fetch of captive {}",
            this.getNpcName(),
            captiveUUID.toString().substring(0, 8)
        );
    }

    /**
     * Start fetching a captive and then delivering to a buyer.
     * This chains FETCHING → DELIVERING automatically.
     *
     * @param captiveUUID The captive to fetch
     * @param buyerUUID The buyer to deliver to
     */
    public void startFetchAndDeliver(UUID captiveUUID, UUID buyerUUID) {
        if (currentState.isBusy()) {
            TiedUpMod.LOGGER.warn(
                "[EntityMaid] {} cannot fetch and deliver - busy with {}",
                this.getNpcName(),
                currentState
            );
            return;
        }

        this.targetCaptiveUUID = captiveUUID;
        this.targetBuyerUUID = buyerUUID;
        setMaidState(MaidState.FETCHING);

        TiedUpMod.LOGGER.info(
            "[EntityMaid] {} starting fetch of captive {} for delivery to buyer {}",
            this.getNpcName(),
            captiveUUID.toString().substring(0, 8),
            buyerUUID.toString().substring(0, 8)
        );
    }

    /**
     * Transition from FETCHING to DELIVERING after capture.
     * Called by MaidFetchCaptiveGoal when it has the captive.
     */
    public void transitionToDelivering() {
        if (targetBuyerUUID == null) {
            // No buyer set - just complete the fetch
            completeTask();
            return;
        }

        // We have a buyer - transition to delivering
        setMaidState(MaidState.DELIVERING);

        TiedUpMod.LOGGER.info(
            "[EntityMaid] {} transitioning to delivery for buyer {}",
            this.getNpcName(),
            targetBuyerUUID.toString().substring(0, 8)
        );
    }

    /**
     * Complete current task and return to idle.
     */
    public void completeTask() {
        TiedUpMod.LOGGER.info(
            "[EntityMaid] {} completed task {}",
            this.getNpcName(),
            currentState
        );

        this.targetCaptiveUUID = null;
        this.targetBuyerUUID = null;
        this.collectTarget = null;
        setMaidState(MaidState.IDLE);
    }

    /**
     * Start patrolling cells to check for escapes and damage.
     */
    public void startPatrol() {
        // Patrol is handled internally by MaidIdleGoal — no state change needed.
        // Setting MaidState.PATROL caused a permanent softlock because no goal
        // ever reset it back to IDLE.
    }

    // PLAYER INTERACTION - MANUAL CHECK-IN

    @Override
    protected InteractionResult mobInteract(
        Player player,
        InteractionHand hand
    ) {
        // Only process main hand to avoid double-triggering
        if (hand != InteractionHand.MAIN_HAND) {
            return super.mobInteract(player, hand);
        }

        if (
            player instanceof ServerPlayer serverPlayer &&
            !isFreed() &&
            level() instanceof ServerLevel serverLevel
        ) {
            // Check if this player is a prisoner of this camp using PrisonerManager
            PrisonerManager manager = PrisonerManager.get(serverLevel);
            PrisonerRecord record = manager.getPrisoner(player.getUUID());

            if (
                record != null &&
                this.getCampUUID() != null &&
                this.getCampUUID().equals(record.getCampId())
            ) {
                // Player is a prisoner of this camp — delegate to prison interaction component
                LaborRecord laborRecord = manager.getLaborRecord(
                    player.getUUID()
                );
                InteractionResult result =
                    prisonInteraction.handlePrisonerInteract(
                        serverPlayer,
                        manager,
                        record,
                        laborRecord
                    );
                if (result != null) {
                    return result;
                }
            }
        }
        return super.mobInteract(player, hand);
    }

    // TARGETING

    @Override
    public boolean isSuitableTarget(
        net.minecraft.world.entity.LivingEntity entity
    ) {
        // If freed, don't target anyone
        if (isFreed()) {
            return false;
        }

        // If trader is under attack, target the attacker
        EntitySlaveTrader trader = getMasterTrader();
        if (trader != null && trader.getLastAttacker() == entity) {
            return true;
        }

        // Otherwise, only target if they attacked us
        return entity == this.getLastAttacker();
    }

    // CAPTURE TIMING (Ultra fast)

    @Override
    public int getCaptureBindTime() {
        return MAID_CAPTURE_TIME_TICKS;
    }

    @Override
    public int getCaptureGagTime() {
        return MAID_CAPTURE_TIME_TICKS;
    }

    // VARIANT SYSTEM

    @Override
    public KidnapperVariant lookupVariantById(String variantId) {
        return MaidSkinManager.CORE.getVariant(variantId);
    }

    @Override
    public KidnapperVariant computeVariantForEntity(UUID entityUUID) {
        return MaidSkinManager.CORE.getVariantForEntity(
            entityUUID,
            Gender.FEMALE
        );
    }

    @Override
    public String getVariantTextureFolder() {
        return "textures/entity/kidnapper/maid/";
    }

    @Override
    public String getDefaultVariantId() {
        return "maid_default";
    }

    @Override
    public String getVariantNBTKey() {
        return "MaidVariantId";
    }

    @Override
    public void applyVariantName(KidnapperVariant variant) {
        // Numbered variants (maid_mob_1, maid_mob_2, etc.) get random names
        // Named variants (maid_default, maid_classic, etc.) use their default name
        if (variant.id().startsWith("maid_mob_")) {
            this.setNpcName(
                com.tiedup.remake.util.NameGenerator.getRandomMaidName()
            );
        } else {
            this.setNpcName(variant.defaultName());
        }
    }

    // DISPLAY

    @Override
    public Component getDisplayName() {
        String suffix = isFreed() ? " (Free)" : "";
        return Component.literal(this.getNpcName() + suffix).withStyle(
            Style.EMPTY.withColor(isFreed() ? 0xAAAAAA : MAID_NAME_COLOR)
        );
    }

    // NBT PERSISTENCE

    @Override
    public void addAdditionalSaveData(CompoundTag tag) {
        super.addAdditionalSaveData(tag);

        traderLink.save(tag);
        tag.putString("MaidState", currentState.name());

        if (targetCaptiveUUID != null) {
            tag.putUUID("TargetCaptiveUUID", targetCaptiveUUID);
        }
        if (targetBuyerUUID != null) {
            tag.putUUID("TargetBuyerUUID", targetBuyerUUID);
        }
        if (collectTarget != null) {
            tag.putInt("CollectTargetX", collectTarget.getX());
            tag.putInt("CollectTargetY", collectTarget.getY());
            tag.putInt("CollectTargetZ", collectTarget.getZ());
        }
        // NOTE: Labor states are now persisted in CampOwnership, not here
    }

    @Override
    public void readAdditionalSaveData(CompoundTag tag) {
        super.readAdditionalSaveData(tag);

        traderLink.load(tag);
        if (tag.contains("MaidState")) {
            try {
                currentState = MaidState.valueOf(tag.getString("MaidState"));
            } catch (IllegalArgumentException e) {
                currentState = MaidState.IDLE;
            }
        }

        if (tag.contains("TargetCaptiveUUID")) {
            targetCaptiveUUID = tag.getUUID("TargetCaptiveUUID");
        }
        if (tag.contains("TargetBuyerUUID")) {
            targetBuyerUUID = tag.getUUID("TargetBuyerUUID");
        }
        if (tag.contains("CollectTargetX")) {
            collectTarget = new BlockPos(
                tag.getInt("CollectTargetX"),
                tag.getInt("CollectTargetY"),
                tag.getInt("CollectTargetZ")
            );
        }
        // NOTE: Labor states are now loaded from CampOwnership, not here
    }

    // GETTERS FOR AI GOALS

    @Nullable
    public UUID getTargetCaptiveUUID() {
        return targetCaptiveUUID;
    }

    @Nullable
    public UUID getTargetBuyerUUID() {
        return targetBuyerUUID;
    }

    @Nullable
    public BlockPos getCollectTarget() {
        return collectTarget;
    }

    // PRISONER STATE ACCESS (facades to MaidPrisonInteraction)

    /**
     * Get the prison interaction component.
     * Exposed for direct component access when needed.
     */
    public MaidPrisonInteraction getPrisonInteraction() {
        return prisonInteraction;
    }

    public Map<UUID, PrisonerRecord> getPrisonerRecords() {
        return prisonInteraction.getPrisonerRecords();
    }

    public Set<UUID> getProcessedPrisoners() {
        return prisonInteraction.getProcessedPrisoners();
    }

    @Nullable
    public CampOwnership getCampOwnership() {
        return prisonInteraction.getCampOwnership();
    }

    @Nullable
    public PrisonerManager getPrisonerManager() {
        return prisonInteraction.getPrisonerManager();
    }

    // STRUGGLE DETECTION (facades to MaidPrisonInteraction)

    public void onStruggleDetected(ServerPlayer prisoner) {
        prisonInteraction.onStruggleDetected(prisoner);
    }

    @Nullable
    public ServerPlayer getStrugglePunishmentTarget() {
        return prisonInteraction.getStrugglePunishmentTarget();
    }

    public void clearStrugglePunishmentTarget() {
        prisonInteraction.clearStrugglePunishmentTarget();
    }

    // DIALOGUE SPEAKER (Maid-specific)

    @Override
    public SpeakerType getSpeakerType() {
        return SpeakerType.MAID;
    }

    @Override
    public PersonalityType getSpeakerPersonality() {
        // Maids are always obedient
        return PersonalityType.SUBMISSIVE;
    }

    @Override
    public int getSpeakerMood() {
        // Mood based on current state
        MaidState maidState = this.getMaidState();
        if (maidState == null) {
            return 50;
        }

        return switch (maidState) {
            case IDLE -> 60; // Calm, waiting for orders
            case FETCHING, DELIVERING -> 50; // Focused on task
            case DEFENDING -> 30; // Serious, protective
            case RETURNING_PRISONER, EXTRACTING_PRISONER -> 55; // Working
            case PATROL -> 55; // Alert
            case COLLECTING, FREE -> 50;
        };
    }
}
