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.util.HumanChairHelper;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.EnumSet;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.AABB;

/**
 * AI Goal for EntityMaster to use the pet as human furniture.
 *
 * The pet is forced on all fours (dogbind pose without visible restraint),
 * frozen in place, while the Master sits on them.
 * Lasts ~2 minutes. During this time the Master does idle behaviors:
 * looks around, comments, observes nearby entities.
 *
 * Flow:
 * 1. APPROACHING: Master walks to pet
 * 2. SETTLING: Master positions on pet, applies pose + freeze
 * 3. SITTING: Main phase - Master sits, does idle stuff
 * 4. GETTING_UP: Master stands, cleanup
 */
public class MasterHumanChairGoal extends Goal {

    private final EntityMaster master;

    /** Duration of the sitting phase (ticks) - ~2 minutes */
    private static final int SITTING_DURATION = 2400;

    /** Time to settle into position (ticks) */
    private static final int SETTLE_DURATION = 40;

    /** Approach distance to start settling */
    private static final double APPROACH_DISTANCE = 1.5;

    /** Interval between idle comments (ticks) */
    private static final int IDLE_COMMENT_INTERVAL = 400; // 20 seconds

    /** Y offset to place the master on the pet's back (compensates sitting animation lowering ~0.25 blocks) */
    private static final double PET_BACK_Y_OFFSET = 0.55;

    /** NBT tag to mark the temporary chair dogbind */
    private static final String NBT_HUMAN_CHAIR_BIND = HumanChairHelper.NBT_KEY;

    private enum Phase {
        APPROACHING,
        SETTLING,
        SITTING,
        GETTING_UP,
    }

    private Phase phase = Phase.APPROACHING;
    private int phaseTimer = 0;
    private int totalTimer = 0;
    private int lastCommentTime = 0;
    private boolean hasAppliedPose = false;
    /** Pet facing direction locked at pose start — decoupled from camera */
    private float lockedPetFacing = 0f;

    /** Persistent look target — refreshed every tick to prevent vanilla LookControl snap-back */
    private double lastLookX, lastLookY, lastLookZ;

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

    @Override
    public boolean canUse() {
        return (
            master.hasPet() &&
            master.getPetPlayer() != null &&
            master.getStateManager().getCurrentState() ==
            MasterState.HUMAN_CHAIR
        );
    }

    @Override
    public boolean canContinueToUse() {
        ServerPlayer pet = master.getPetPlayer();
        return (
            pet != null &&
            pet.isAlive() &&
            master.getStateManager().getCurrentState() ==
            MasterState.HUMAN_CHAIR &&
            phase != Phase.GETTING_UP
        );
    }

    @Override
    public void start() {
        this.phase = Phase.APPROACHING;
        this.phaseTimer = 0;
        this.totalTimer = 0;
        this.lastCommentTime = 0;
        this.hasAppliedPose = false;

        TiedUpMod.LOGGER.debug(
            "[MasterHumanChairGoal] {} starting human chair",
            master.getNpcName()
        );
    }

    @Override
    public void stop() {
        // Cleanup: remove pose, effects, and standing up
        cleanupPetPose();

        // Master stands up
        master.setSitting(false);
        master.setNoGravity(false);
        master.noPhysics = false;
        // Return to following
        if (master.hasPet()) {
            master.setMasterState(MasterState.FOLLOWING);
        }

        this.phase = Phase.APPROACHING;
        this.phaseTimer = 0;
        this.totalTimer = 0;
        this.hasAppliedPose = false;

        TiedUpMod.LOGGER.debug(
            "[MasterHumanChairGoal] {} ended human chair",
            master.getNpcName()
        );
    }

    @Override
    public void tick() {
        ServerPlayer pet = master.getPetPlayer();
        if (pet == null) return;

        totalTimer++;

        switch (phase) {
            case APPROACHING -> tickApproaching(pet);
            case SETTLING -> tickSettling(pet);
            case SITTING -> tickSitting(pet);
            case GETTING_UP -> {
            } // handled by canContinueToUse returning false
        }
    }

    // PHASE: APPROACHING

    private void tickApproaching(ServerPlayer pet) {
        master.getLookControl().setLookAt(pet, 30.0F, 30.0F);

        double distSq = master.distanceToSqr(pet);
        if (distSq > APPROACH_DISTANCE * APPROACH_DISTANCE) {
            master.getNavigation().moveTo(pet, 1.0);
        } else {
            // Close enough - start settling
            master.getNavigation().stop();
            phase = Phase.SETTLING;
            phaseTimer = 0;

            // Tell pet what's about to happen
            DialogueBridge.talkTo(master, pet, "petplay.human_chair_command");
        }
    }

    // PHASE: SETTLING

    private void tickSettling(ServerPlayer pet) {
        master.getLookControl().setLookAt(pet, 30.0F, 30.0F);
        master.getNavigation().stop();

        // Apply the pose on first tick of settling
        if (!hasAppliedPose) {
            lockedPetFacing = pet.getYRot();
            applyPetPose(pet);
            hasAppliedPose = true;
        }

        phaseTimer++;

        if (phaseTimer >= SETTLE_DURATION) {
            // Settled - Master sits down
            master.setSitting(true);
            master.setNoGravity(true);
            master.noPhysics = true;

            // Position master centered on pet's back
            positionOnPet(pet);

            // Initialize look target: forward along sideways direction
            float sideYaw = lockedPetFacing + 90f;
            float sideRad = (float) Math.toRadians(sideYaw);
            lastLookX = master.getX() + (-Math.sin(sideRad)) * 5;
            lastLookY = master.getEyeY();
            lastLookZ = master.getZ() + Math.cos(sideRad) * 5;

            phase = Phase.SITTING;
            phaseTimer = 0;
            lastCommentTime = totalTimer;

            DialogueBridge.talkTo(master, pet, "petplay.human_chair_sitting");

            TiedUpMod.LOGGER.debug(
                "[MasterHumanChairGoal] {} settled on {}",
                master.getNpcName(),
                pet.getName().getString()
            );
        }
    }

    // PHASE: SITTING

    private void tickSitting(ServerPlayer pet) {
        phaseTimer++;

        // Force master position on pet every tick to prevent drifting
        positionOnPet(pet);

        // Refresh slowness to keep pet frozen
        if (phaseTimer % 60 == 0) {
            pet.addEffect(
                new MobEffectInstance(
                    MobEffects.MOVEMENT_SLOWDOWN,
                    80,
                    255,
                    false,
                    false,
                    false
                )
            );
            pet.addEffect(
                new MobEffectInstance(
                    MobEffects.JUMP,
                    80,
                    128,
                    false,
                    false,
                    false
                )
            );
        }

        // Idle behaviors during sitting (may update lastLook target)
        tickIdleBehavior(pet);

        // Refresh look target every tick to prevent vanilla LookControl snap-back
        // (vanilla lookAtCooldown = 2 → target expires after 2 ticks → head snaps to center)
        master
            .getLookControl()
            .setLookAt(lastLookX, lastLookY, lastLookZ, 10f, 10f);

        // Check if duration expired
        if (phaseTimer >= SITTING_DURATION) {
            phase = Phase.GETTING_UP;

            DialogueBridge.talkTo(master, pet, "petplay.human_chair_end");

            TiedUpMod.LOGGER.debug(
                "[MasterHumanChairGoal] {} getting up from {}",
                master.getNpcName(),
                pet.getName().getString()
            );
        }
    }

    // IDLE BEHAVIORS DURING SITTING

    private void tickIdleBehavior(ServerPlayer pet) {
        // Periodically look at nearby entities or comment
        if (totalTimer - lastCommentTime >= IDLE_COMMENT_INTERVAL) {
            lastCommentTime = totalTimer;

            // 50% chance: look at a nearby entity, 50% chance: idle comment
            if (master.getRandom().nextFloat() < 0.5f) {
                lookAtNearbyEntity(pet);
            } else {
                // Idle comment about sitting/pet
                String[] idleDialogues = {
                    "petplay.human_chair_idle",
                    "idle.content",
                    "idle.observing",
                };
                String dialogue = idleDialogues[master
                    .getRandom()
                    .nextInt(idleDialogues.length)];
                DialogueBridge.talkTo(master, pet, dialogue);
            }
        }

        // Between comments, slowly look around
        if (phaseTimer % 100 == 0) {
            float randomYaw =
                master.getYRot() +
                (master.getRandom().nextFloat() - 0.5f) * 120;
            lastLookX = master.getX() + Math.sin(Math.toRadians(randomYaw)) * 5;
            lastLookY = master.getEyeY();
            lastLookZ = master.getZ() + Math.cos(Math.toRadians(randomYaw)) * 5;
        }
    }

    /**
     * Look at a random nearby living entity (NPC, player, mob).
     */
    private void lookAtNearbyEntity(ServerPlayer pet) {
        AABB searchBox = master.getBoundingBox().inflate(12.0);
        var nearbyEntities = master
            .level()
            .getEntitiesOfClass(
                LivingEntity.class,
                searchBox,
                e -> e != master && e != pet && e.isAlive()
            );

        if (!nearbyEntities.isEmpty()) {
            LivingEntity target = nearbyEntities.get(
                master.getRandom().nextInt(nearbyEntities.size())
            );
            lastLookX = target.getX();
            lastLookY = target.getEyeY();
            lastLookZ = target.getZ();

            // Comment about the entity
            if (target instanceof Player) {
                DialogueBridge.talkTo(
                    master,
                    pet,
                    "petplay.human_chair_notice_player"
                );
            } else {
                DialogueBridge.talkTo(
                    master,
                    pet,
                    "petplay.human_chair_notice_entity"
                );
            }
        }
    }

    // POSITIONING

    /**
     * Position master on pet's back, facing sideways (perpendicular).
     * Called every tick during SITTING to prevent any drift from collision/physics.
     * Body rotation is locked so only the head turns when looking at entities.
     */
    private void positionOnPet(ServerPlayer pet) {
        // Use locked facing — decoupled from player camera
        float petYaw = (float) Math.toRadians(lockedPetFacing);
        double offsetX = -Math.sin(petYaw) * 0.15;
        double offsetZ = Math.cos(petYaw) * 0.15;

        // Face perpendicular to the pet (sitting sideways)
        float sideYaw = lockedPetFacing + 90f;

        master.moveTo(
            pet.getX() + offsetX,
            pet.getY() + PET_BACK_Y_OFFSET,
            pet.getZ() + offsetZ,
            sideYaw,
            0.0F
        );

        // Lock body rotation so look-at only turns the head
        master.yBodyRot = sideYaw;
        master.yBodyRotO = sideYaw;

        // Zero out velocity to prevent physics drift
        master.setDeltaMovement(0, 0, 0);
    }

    // POSE MANAGEMENT

    /**
     * Apply the human chair pose to the pet:
     * - Temporary invisible dogbind for the on-all-fours animation
     * - Slowness 255 to freeze movement
     * - Jump boost negative to prevent jumping
     */
    private void applyPetPose(ServerPlayer pet) {
        PlayerBindState bindState = PlayerBindState.getInstance(pet);
        if (bindState == null) return;

        // Apply invisible dogbind for the pose animation
        if (!bindState.isTiedUp()) {
            ItemStack dogbind = DataDrivenBondageItem.createStack(
                ResourceLocation.fromNamespaceAndPath("tiedup", "dogbinder")
            );
            CompoundTag tag = dogbind.getOrCreateTag();
            tag.putBoolean(NBT_HUMAN_CHAIR_BIND, true);
            tag.putBoolean("tempMasterEvent", true);
            tag.putLong(
                "expirationTime",
                master.level().getGameTime() + SITTING_DURATION + 200
            );
            tag.putUUID("masterUUID", master.getUUID());
            tag.putFloat(HumanChairHelper.NBT_FACING_KEY, pet.getYRot());
            bindState.equip(BodyRegionV2.ARMS, dogbind);
        }

        // Freeze the pet
        pet.addEffect(
            new MobEffectInstance(
                MobEffects.MOVEMENT_SLOWDOWN,
                SITTING_DURATION + 100,
                255,
                false,
                false,
                false
            )
        );
        pet.addEffect(
            new MobEffectInstance(
                MobEffects.JUMP,
                SITTING_DURATION + 100,
                128,
                false,
                false,
                false
            )
        );

        TiedUpMod.LOGGER.debug(
            "[MasterHumanChairGoal] Applied chair pose to {}",
            pet.getName().getString()
        );
    }

    /**
     * Remove the human chair pose from the pet.
     */
    private void cleanupPetPose() {
        ServerPlayer pet = master.getPetPlayer();
        if (pet == null) return;

        // Remove the temporary dogbind
        PlayerBindState bindState = PlayerBindState.getInstance(pet);
        if (bindState != null && bindState.isTiedUp()) {
            ItemStack bind = bindState.getEquipment(BodyRegionV2.ARMS);
            if (!bind.isEmpty()) {
                CompoundTag tag = bind.getTag();
                if (tag != null && tag.getBoolean(NBT_HUMAN_CHAIR_BIND)) {
                    bindState.unequip(BodyRegionV2.ARMS);
                    TiedUpMod.LOGGER.debug(
                        "[MasterHumanChairGoal] Removed chair bind from {}",
                        pet.getName().getString()
                    );
                }
            }
        }

        // Remove slowness and jump effects
        pet.removeEffect(MobEffects.MOVEMENT_SLOWDOWN);
        pet.removeEffect(MobEffects.JUMP);
    }

    /**
     * Check if an item is a human chair temporary bind.
     */
    public static boolean isHumanChairBind(ItemStack stack) {
        if (stack.isEmpty()) return false;
        CompoundTag tag = stack.getTag();
        return tag != null && tag.getBoolean(NBT_HUMAN_CHAIR_BIND);
    }
}
