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 java.util.EnumSet;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.phys.Vec3;

/**
 * AI Goal for EntityMaster to perform idle micro-behaviors.
 *
 * Fills the gap between tasks/events with small, natural-looking actions.
 * Lower priority than tasks/events/inspect, but higher than look-at goals.
 */
public class MasterIdleBehaviorGoal extends Goal {

    private final EntityMaster master;

    /** Chance to start idle behavior per tick */
    private static final float IDLE_CHANCE = 0.003f; // ~6% per 10 seconds

    /** Minimum time between idle behaviors (ticks) - 20 seconds */
    private static final int IDLE_COOLDOWN = 400;

    /** Distance to approach pet for close behaviors */
    private static final double APPROACH_DISTANCE = 2.0;

    /** Distance to walk away for CHECK_SURROUNDINGS */
    private static final double SCOUT_DISTANCE = 8.0;

    /**
     * Types of idle micro-behaviors.
     */
    private enum IdleBehavior {
        LOOK_AROUND(60), // 3s - random look angles
        EXAMINE_PET(80), // 4s - walk to pet, stare
        PAT_HEAD(60), // 3s - approach, pat, step back
        ADJUST_COLLAR(60), // 3s - approach, adjust collar dialogue
        IDLE_COMMENT(20), // 1s - random idle comment
        STRETCH(40), // 2s - stop, do nothing
        CHECK_SURROUNDINGS(100); // 5s - walk away, look around, return

        final int duration;

        IdleBehavior(int duration) {
            this.duration = duration;
        }
    }

    private long lastIdleTime = 0;
    private IdleBehavior currentBehavior = null;
    private int behaviorTimer = 0;
    private boolean hasPerformedAction = false;

    /** For CHECK_SURROUNDINGS: the position to walk to */
    private Vec3 scoutTarget = null;
    /** For CHECK_SURROUNDINGS: whether we've reached the scout target */
    private boolean reachedScoutTarget = false;

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

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

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

        // Only idle behaviors from FOLLOWING or OBSERVING
        if (state != MasterState.FOLLOWING && state != MasterState.OBSERVING) {
            return false;
        }

        // No idle behaviors if there's an active task
        if (master.hasActiveTask()) return false;

        // No idle behaviors during cold shoulder
        if (master.isGivingColdShoulder()) return false;

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

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

    @Override
    public boolean canContinueToUse() {
        if (!master.hasPet()) return false;
        if (currentBehavior == null) return false;
        if (behaviorTimer >= currentBehavior.duration) return false;

        MasterState state = master.getStateManager().getCurrentState();
        return state == MasterState.FOLLOWING || state == MasterState.OBSERVING;
    }

    @Override
    public void start() {
        this.behaviorTimer = 0;
        this.hasPerformedAction = false;
        this.scoutTarget = null;
        this.reachedScoutTarget = false;

        // Select random idle behavior
        IdleBehavior[] behaviors = IdleBehavior.values();
        this.currentBehavior = behaviors[master
            .getRandom()
            .nextInt(behaviors.length)];

        TiedUpMod.LOGGER.debug(
            "[MasterIdleBehaviorGoal] {} starting idle: {}",
            master.getNpcName(),
            currentBehavior
        );
    }

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

        this.currentBehavior = null;
        this.behaviorTimer = 0;
        this.hasPerformedAction = false;
        this.scoutTarget = null;
        this.reachedScoutTarget = false;

        master.getNavigation().stop();
    }

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

        behaviorTimer++;

        switch (currentBehavior) {
            case LOOK_AROUND -> tickLookAround();
            case EXAMINE_PET -> tickExaminePet(pet);
            case PAT_HEAD -> tickPatHead(pet);
            case ADJUST_COLLAR -> tickAdjustCollar(pet);
            case IDLE_COMMENT -> tickIdleComment(pet);
            case STRETCH -> tickStretch();
            case CHECK_SURROUNDINGS -> tickCheckSurroundings(pet);
        }
    }

    private void tickLookAround() {
        // Randomly change look direction every 20 ticks
        if (behaviorTimer % 20 == 1) {
            float yaw =
                master.getYRot() +
                (master.getRandom().nextFloat() - 0.5f) * 120;
            float pitch = (master.getRandom().nextFloat() - 0.5f) * 40;
            master
                .getLookControl()
                .setLookAt(
                    master.getX() + Math.sin(Math.toRadians(-yaw)) * 5,
                    master.getEyeY() + pitch * 0.1,
                    master.getZ() + Math.cos(Math.toRadians(-yaw)) * 5
                );
        }
        master.getNavigation().stop();
    }

    private void tickExaminePet(ServerPlayer pet) {
        double dist = master.distanceTo(pet);
        if (dist > APPROACH_DISTANCE) {
            master.getNavigation().moveTo(pet, 0.8);
        } else {
            master.getNavigation().stop();
            master.getLookControl().setLookAt(pet, 30.0F, 30.0F);

            if (!hasPerformedAction) {
                DialogueBridge.talkTo(master, pet, "idle.examine");
                hasPerformedAction = true;
            }
        }
    }

    private void tickPatHead(ServerPlayer pet) {
        double dist = master.distanceTo(pet);
        if (dist > APPROACH_DISTANCE) {
            master.getNavigation().moveTo(pet, 0.8);
        } else {
            master.getNavigation().stop();
            master.getLookControl().setLookAt(pet, 30.0F, 30.0F);

            if (!hasPerformedAction) {
                DialogueBridge.talkTo(master, pet, "idle.pat_head");
                hasPerformedAction = true;
            }
        }
    }

    private void tickAdjustCollar(ServerPlayer pet) {
        double dist = master.distanceTo(pet);
        if (dist > APPROACH_DISTANCE) {
            master.getNavigation().moveTo(pet, 0.8);
        } else {
            master.getNavigation().stop();
            master.getLookControl().setLookAt(pet, 30.0F, 30.0F);

            if (!hasPerformedAction) {
                DialogueBridge.talkTo(master, pet, "idle.adjust_collar");
                hasPerformedAction = true;
            }
        }
    }

    private void tickIdleComment(ServerPlayer pet) {
        master.getNavigation().stop();
        if (!hasPerformedAction) {
            // Pick randomly between existing idle dialogues
            String dialogueId = master.getRandom().nextBoolean()
                ? "idle.content"
                : "idle.bored";
            DialogueBridge.talkTo(master, pet, dialogueId);
            hasPerformedAction = true;
        }
    }

    private void tickStretch() {
        // Do nothing - natural pause
        master.getNavigation().stop();
    }

    private void tickCheckSurroundings(ServerPlayer pet) {
        if (scoutTarget == null) {
            // Pick a random direction to walk
            double angle = master.getRandom().nextDouble() * Math.PI * 2;
            double dist = 5 + master.getRandom().nextDouble() * 3; // 5-8 blocks
            scoutTarget = new Vec3(
                master.getX() + Math.cos(angle) * dist,
                master.getY(),
                master.getZ() + Math.sin(angle) * dist
            );
        }

        if (!reachedScoutTarget) {
            // Walk to scout target
            master
                .getNavigation()
                .moveTo(scoutTarget.x, scoutTarget.y, scoutTarget.z, 0.8);

            // Check if we arrived or enough time passed
            double distToTarget = master.position().distanceTo(scoutTarget);
            if (
                distToTarget < 2.0 ||
                behaviorTimer > currentBehavior.duration / 2
            ) {
                reachedScoutTarget = true;
                master.getNavigation().stop();

                if (!hasPerformedAction) {
                    DialogueBridge.talkTo(
                        master,
                        pet,
                        "idle.check_surroundings"
                    );
                    hasPerformedAction = true;
                }
            }
        } else {
            // Look around at scout target, then return is handled by goal ending
            // (follow goal will bring master back to pet)
            if (behaviorTimer % 20 == 0) {
                float yaw =
                    master.getYRot() +
                    (master.getRandom().nextFloat() - 0.5f) * 180;
                master
                    .getLookControl()
                    .setLookAt(
                        master.getX() + Math.sin(Math.toRadians(-yaw)) * 5,
                        master.getEyeY(),
                        master.getZ() + Math.cos(Math.toRadians(-yaw)) * 5
                    );
            }
        }
    }
}
