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

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.dialogue.DialogueBridge;
import com.tiedup.remake.entities.EntityMaster;
import com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem;
import net.minecraft.resources.ResourceLocation;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.v2.bondage.IV2BondageEquipment;
import com.tiedup.remake.v2.bondage.capability.V2EquipmentHelper;
import java.util.EnumSet;
import java.util.List;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.item.ItemStack;

/**
 * AI Goal for EntityMaster to trigger random events:
 * - Random bind/accessory placement (temporary)
 * - Master-initiated dogwalk
 *
 * Events are less frequent than tasks and add variety to gameplay.
 */
public class MasterRandomEventGoal extends Goal {

    private final EntityMaster master;

    /** Chance to trigger an event per tick */
    private static final float EVENT_CHANCE = 0.002f; // ~4% per 10 seconds

    /** Minimum time between events (ticks) - 2 minutes */
    private static final int EVENT_COOLDOWN = 2400;

    /** Duration of random bind event (ticks) - 2 minutes */
    private static final int RANDOM_BIND_DURATION = 2400;

    /** NBT tag key for temporary master event items */
    private static final String NBT_TEMP_MASTER_EVENT = "tempMasterEvent";
    private static final String NBT_EXPIRATION_TIME = "expirationTime";

    /** Event types that can be triggered randomly */
    private enum RandomEvent {
        RANDOM_BIND,
        DOGWALK,
        HUMAN_CHAIR,
    }

    /** Accessory regions that can be randomly equipped (eyes, mouth, hands) */
    private static final List<BodyRegionV2> RANDOM_ACCESSORY_REGIONS = List.of(
        BodyRegionV2.EYES,
        BodyRegionV2.MOUTH,
        BodyRegionV2.HANDS
    );

    private long lastEventTime = 0;
    private RandomEvent currentEvent = null;
    private int eventTimer = 0;

    /** For RANDOM_BIND: the body region that was equipped */
    private BodyRegionV2 appliedAccessoryRegion = null;
    private ItemStack appliedAccessory = ItemStack.EMPTY;

    public MasterRandomEventGoal(EntityMaster master) {
        this.master = master;
        this.setFlags(EnumSet.of(Goal.Flag.LOOK));
    }

    @Override
    public boolean canUse() {
        if (!master.hasPet()) return false;

        MasterState state = master.getStateManager().getCurrentState();

        // Don't trigger events during other activities
        if (state != MasterState.FOLLOWING && state != MasterState.OBSERVING) {
            return false;
        }

        // Don't trigger if there's an active task
        if (master.hasActiveTask()) return false;

        // Check cooldown
        long currentTime = master.level().getGameTime();
        if (currentTime - lastEventTime < EVENT_COOLDOWN) {
            return false;
        }

        // Random chance (modulated by engagement cadence)
        float multiplier = master.getEngagementMultiplier();
        return (
            multiplier > 0 &&
            master.getRandom().nextFloat() < EVENT_CHANCE * multiplier
        );
    }

    @Override
    public boolean canContinueToUse() {
        // Only continue for timed events like RANDOM_BIND
        return (
            currentEvent == RandomEvent.RANDOM_BIND &&
            eventTimer < RANDOM_BIND_DURATION
        );
    }

    @Override
    public void start() {
        this.eventTimer = 0;
        this.appliedAccessoryRegion = null;
        this.appliedAccessory = ItemStack.EMPTY;

        // Select random event
        RandomEvent[] events = RandomEvent.values();
        this.currentEvent = events[master.getRandom().nextInt(events.length)];

        master.markEngagement();
        triggerEvent();

        TiedUpMod.LOGGER.debug(
            "[MasterRandomEventGoal] {} triggered event: {}",
            master.getNpcName(),
            currentEvent
        );
    }

    @Override
    public void stop() {
        lastEventTime = master.level().getGameTime();

        // Only remove accessory on natural completion (timer expired),
        // NOT on goal preemption (e.g. MasterObservePlayerGoal taking over LOOK flag).
        // If preempted, the NBT expiration timer in cleanupExpiredTempItems() handles removal.
        if (
            currentEvent == RandomEvent.RANDOM_BIND &&
            appliedAccessoryRegion != null &&
            eventTimer >= RANDOM_BIND_DURATION
        ) {
            removeAppliedAccessory();
        }

        this.currentEvent = null;
        this.eventTimer = 0;
        this.appliedAccessoryRegion = null;
        this.appliedAccessory = ItemStack.EMPTY;

        TiedUpMod.LOGGER.debug(
            "[MasterRandomEventGoal] {} event completed",
            master.getNpcName()
        );
    }

    @Override
    public void tick() {
        if (currentEvent == RandomEvent.RANDOM_BIND) {
            eventTimer++;
        }
    }

    /**
     * Trigger the selected event.
     */
    private void triggerEvent() {
        ServerPlayer pet = master.getPetPlayer();
        if (pet == null) return;

        switch (currentEvent) {
            case RANDOM_BIND -> triggerRandomBind(pet);
            case DOGWALK -> triggerDogwalk(pet);
            case HUMAN_CHAIR -> triggerHumanChair(pet);
        }
    }

    /**
     * Trigger random bind event - apply a temporary accessory.
     */
    private void triggerRandomBind(ServerPlayer pet) {
        PlayerBindState bindState = PlayerBindState.getInstance(pet);
        if (bindState == null) return;

        // Collect all empty accessory regions, then pick one at random
        List<BodyRegionV2> emptyRegions = new java.util.ArrayList<>();
        for (BodyRegionV2 region : RANDOM_ACCESSORY_REGIONS) {
            if (!V2EquipmentHelper.isRegionOccupied(pet, region)) {
                emptyRegions.add(region);
            }
        }

        BodyRegionV2 selectedRegion = null;
        if (!emptyRegions.isEmpty()) {
            selectedRegion = emptyRegions.get(
                master.getRandom().nextInt(emptyRegions.size())
            );
        } else if (master.getRandom().nextFloat() < 0.3f) {
            // If no empty region, pick random and replace (less likely)
            selectedRegion = RANDOM_ACCESSORY_REGIONS.get(
                master.getRandom().nextInt(RANDOM_ACCESSORY_REGIONS.size())
            );
        }

        if (selectedRegion == null) {
            // Pet is fully accessorized, skip event
            currentEvent = null;
            return;
        }

        // Create the accessory item
        ItemStack accessory = createRandomAccessory(selectedRegion);
        if (accessory.isEmpty()) {
            currentEvent = null;
            return;
        }

        // Mark the accessory as temporary with expiration time
        // This ensures cleanup even after server restart
        long expirationTime =
            master.level().getGameTime() + RANDOM_BIND_DURATION;
        CompoundTag tag = accessory.getOrCreateTag();
        tag.putBoolean(NBT_TEMP_MASTER_EVENT, true);
        tag.putLong(NBT_EXPIRATION_TIME, expirationTime);
        tag.putUUID("masterUUID", master.getUUID());

        // Apply the accessory
        this.appliedAccessoryRegion = selectedRegion;
        this.appliedAccessory = accessory;

        IV2BondageEquipment equip = V2EquipmentHelper.getEquipment(pet);
        if (equip != null) {
            equip.setInRegion(selectedRegion, accessory);
            V2EquipmentHelper.sync(pet);
        }

        // Dialogue - both messages sent (random_bind is the action, random_bind_done is the completion)
        DialogueBridge.talkTo(master, pet, "petplay.random_bind");

        TiedUpMod.LOGGER.debug(
            "[MasterRandomEventGoal] {} applied {} to {}",
            master.getNpcName(),
            selectedRegion,
            pet.getName().getString()
        );
    }

    /**
     * Create a random accessory item for the given body region.
     */
    private ItemStack createRandomAccessory(BodyRegionV2 region) {
        return switch (region) {
            case EYES -> DataDrivenBondageItem.createStack(
                ResourceLocation.fromNamespaceAndPath("tiedup", "classic_blindfold")
            );
            case MOUTH -> DataDrivenBondageItem.createStack(
                ResourceLocation.fromNamespaceAndPath("tiedup", "ball_gag")
            );
            case HANDS -> DataDrivenBondageItem.createStack(
                ResourceLocation.fromNamespaceAndPath("tiedup", "leather_mittens")
            );
            default -> ItemStack.EMPTY;
        };
    }

    /**
     * Remove the applied accessory when event ends.
     */
    private void removeAppliedAccessory() {
        ServerPlayer pet = master.getPetPlayer();
        if (pet == null) return;

        if (appliedAccessoryRegion != null) {
            // Check if it's still the same item we applied
            ItemStack current = V2EquipmentHelper.getInRegion(
                pet,
                appliedAccessoryRegion
            );
            if (current.getItem() == appliedAccessory.getItem()) {
                V2EquipmentHelper.unequipFromRegion(
                    pet,
                    appliedAccessoryRegion,
                    true
                );

                // Dialogue
                DialogueBridge.talkTo(
                    master,
                    pet,
                    "petplay.random_bind_remove"
                );

                TiedUpMod.LOGGER.debug(
                    "[MasterRandomEventGoal] {} removed {} from {}",
                    master.getNpcName(),
                    appliedAccessoryRegion,
                    pet.getName().getString()
                );
            }
        }
    }

    /**
     * Trigger dogwalk event - Master initiates a walk.
     */
    private void triggerDogwalk(ServerPlayer pet) {
        // Put pet in dogbind if not already tied
        PlayerBindState bindState = PlayerBindState.getInstance(pet);
        if (bindState != null && !bindState.isTiedUp()) {
            ItemStack dogbind = DataDrivenBondageItem.createStack(
                ResourceLocation.fromNamespaceAndPath("tiedup", "dogbinder")
            );
            bindState.equip(BodyRegionV2.ARMS, dogbind);
        }

        // Attach leash
        master.attachLeashToPet();

        // Set dogwalk mode - master leads (pulls the pet)
        master.setDogwalkMode(true);
        master.setMasterState(MasterState.DOGWALK);

        // Dialogue
        DialogueBridge.talkTo(master, pet, "petplay.start_dogwalk");

        TiedUpMod.LOGGER.debug(
            "[MasterRandomEventGoal] {} started dogwalk with {}",
            master.getNpcName(),
            pet.getName().getString()
        );

        // Event is instant - dogwalk continues until manually ended or timeout
        this.currentEvent = null; // Don't continue in this goal
    }

    /**
     * Trigger human chair event - Master uses pet as furniture.
     * Delegates to MasterHumanChairGoal for the actual behavior.
     */
    private void triggerHumanChair(ServerPlayer pet) {
        // Don't trigger if pet is already tied up (dogbind would conflict)
        PlayerBindState bindState = PlayerBindState.getInstance(pet);
        if (bindState != null && bindState.isTiedUp()) {
            // Fall back to random bind instead
            currentEvent = RandomEvent.RANDOM_BIND;
            triggerRandomBind(pet);
            return;
        }

        // Set state - MasterHumanChairGoal will handle the rest
        master.setMasterState(MasterState.HUMAN_CHAIR);

        // Dialogue
        DialogueBridge.talkTo(master, pet, "petplay.human_chair_start");

        TiedUpMod.LOGGER.debug(
            "[MasterRandomEventGoal] {} started human chair with {}",
            master.getNpcName(),
            pet.getName().getString()
        );

        // Event is instant - human chair continues in dedicated goal
        this.currentEvent = null;
    }

    // STATIC CLEANUP METHODS

    /** All body regions that can have temporary master event items */
    private static final List<BodyRegionV2> TEMP_ITEM_CLEANUP_REGIONS = List.of(
        BodyRegionV2.ARMS,
        BodyRegionV2.EYES,
        BodyRegionV2.MOUTH,
        BodyRegionV2.HANDS
    );

    /**
     * Check and cleanup any expired temporary master event items on a player.
     * Should be called periodically from EntityMaster.tick() or on player login.
     *
     * @param pet The player to check
     * @param currentTime Current game time
     */
    public static void cleanupExpiredTempItems(
        ServerPlayer pet,
        long currentTime
    ) {
        for (BodyRegionV2 region : TEMP_ITEM_CLEANUP_REGIONS) {
            ItemStack item = V2EquipmentHelper.getInRegion(pet, region);
            if (item.isEmpty()) continue;

            CompoundTag tag = item.getTag();
            if (tag == null) continue;

            if (tag.getBoolean(NBT_TEMP_MASTER_EVENT)) {
                long expirationTime = tag.getLong(NBT_EXPIRATION_TIME);
                if (currentTime >= expirationTime) {
                    // Item expired - use proper removal to trigger onUnequipped callbacks
                    // ARMS (bind) needs PlayerBindState.unequip(BodyRegionV2.ARMS) for speed/animation cleanup
                    if (region == BodyRegionV2.ARMS) {
                        PlayerBindState bindState = PlayerBindState.getInstance(
                            pet
                        );
                        if (bindState != null && bindState.isTiedUp()) {
                            bindState.unequip(BodyRegionV2.ARMS);
                        }
                    } else {
                        V2EquipmentHelper.unequipFromRegion(pet, region, true);
                    }

                    TiedUpMod.LOGGER.info(
                        "[MasterRandomEventGoal] Removed expired temp {} from {}",
                        region,
                        pet.getName().getString()
                    );
                }
            }
        }
    }

    /**
     * Check if an item is a temporary master event item.
     */
    public static boolean isTempMasterEventItem(ItemStack stack) {
        if (stack.isEmpty()) return false;
        CompoundTag tag = stack.getTag();
        return tag != null && tag.getBoolean(NBT_TEMP_MASTER_EVENT);
    }
}
