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.CollarHelper;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.util.MessageDispatcher;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.EnumSet;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;

/**
 * AI Goal for EntityMaster to watch and enforce active tasks.
 *
 * Monitors task compliance and triggers choke collar punishment on violation:
 * - HEEL: Player must stay within 3 blocks of Master
 * - WAIT_HERE: Player must not move more than 1 block from start position
 * - FETCH_ITEM: Player must give item within time limit (handled separately via interaction)
 */
public class MasterTaskWatchGoal extends Goal {

    private final EntityMaster master;

    /** Ticks between compliance checks */
    private static final int CHECK_INTERVAL = 10;

    /** Choke duration on violation (ticks) - 2 seconds */
    private static final int CHOKE_DURATION = 40;

    /** Grace period before starting to check (ticks) - 3 seconds */
    private static final int GRACE_PERIOD = 60;

    /** Warning messages when task is violated */
    private static final String[] HEEL_VIOLATION_MESSAGES = {
        "You're too far! Heel!",
        "Stay close, pet!",
        "*tugs at your collar*",
    };

    private static final String[] WAIT_VIOLATION_MESSAGES = {
        "I said don't move!",
        "Stay still!",
        "*activates your collar*",
    };

    private static final String[] KNEEL_VIOLATION_MESSAGES = {
        "I said kneel!",
        "Get back down!",
        "On your knees, pet!",
    };

    private static final String[] COME_VIOLATION_MESSAGES = {
        "Too slow!",
        "I said come HERE!",
        "You're taking too long!",
    };

    private static final String[] PRESENT_VIOLATION_MESSAGES = {
        "Stand still!",
        "Don't move away from me!",
        "Present yourself properly!",
    };

    private static final String[] DROP_VIOLATION_MESSAGES = {
        "Drop it!",
        "Empty your hands. Now.",
        "I said drop what you're holding!",
    };

    private static final String[] FOLLOW_CLOSE_VIOLATION_MESSAGES = {
        "Closer!",
        "Stay right beside me!",
        "*yanks your collar*",
    };

    private int checkTimer = 0;
    private int taskTimer = 0;
    private int chokeTimer = 0;
    private ItemStack activeChokeCollar = ItemStack.EMPTY;

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

    @Override
    public boolean canUse() {
        // Only active in TASK_WATCH state with an active task
        return (
            master.getStateManager().getCurrentState() ==
                MasterState.TASK_WATCH &&
            master.hasPet() &&
            master.hasActiveTask()
        );
    }

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

        ServerPlayer pet = master.getPetPlayer();
        if (pet == null || !pet.isAlive()) return false;

        // Continue while in TASK_WATCH state
        if (
            master.getStateManager().getCurrentState() != MasterState.TASK_WATCH
        ) {
            return false;
        }

        // Check if task duration expired
        PetTask task = master.getCurrentTask();
        if (
            task != null &&
            task.getDurationTicks() > 0 &&
            taskTimer >= task.getDurationTicks()
        ) {
            return false;
        }

        return master.hasActiveTask();
    }

    @Override
    public void start() {
        this.checkTimer = 0;
        this.taskTimer = 0;
        this.chokeTimer = 0;
        this.activeChokeCollar = ItemStack.EMPTY;

        TiedUpMod.LOGGER.debug(
            "[MasterTaskWatchGoal] {} started watching task: {}",
            master.getNpcName(),
            master.getCurrentTask()
        );
    }

    @Override
    public void stop() {
        // Ensure choke is deactivated
        deactivateChoke();

        // Check if task completed successfully
        PetTask task = master.getCurrentTask();

        // Determine success based on task type
        boolean success = false;
        ServerPlayer pet = master.getPetPlayer();

        if (
            task != null &&
            task.getDurationTicks() > 0 &&
            taskTimer >= task.getDurationTicks()
        ) {
            // Duration expired - check end-state success for specific tasks
            switch (task) {
                case FETCH_ITEM, DEMAND -> {
                    // Reaching timeout = failure (success handled via handleFetchItemGive/mobInteract)
                    success = false;
                }
                case SPEAK -> {
                    // Reaching timeout = failure (success handled via mobInteract)
                    success = false;
                }
                case COME -> {
                    // Success if pet is within range at end
                    success =
                        pet != null &&
                        master.distanceTo(pet) <= task.getMaxDistance();
                }
                case DROP -> {
                    // Success if hands are empty at end
                    success =
                        pet != null &&
                        pet.getMainHandItem().isEmpty() &&
                        pet.getOffhandItem().isEmpty();
                }
                default -> {
                    // Duration-based tasks: completing duration IS success
                    success = true;
                }
            }
        }

        if (success) {
            if (pet != null) {
                DialogueBridge.talkTo(master, pet, "petplay.task_complete");
                TiedUpMod.LOGGER.debug(
                    "[MasterTaskWatchGoal] {} completed task {} successfully",
                    pet.getName().getString(),
                    task
                );
            }
        } else if (
            task != null &&
            task.getDurationTicks() > 0 &&
            taskTimer >= task.getDurationTicks()
        ) {
            // Task timed out without success
            if (pet != null) {
                DialogueBridge.talkTo(master, pet, "petplay.disappointed");
                // Trigger punishment for failure
                master.setMasterState(MasterState.PUNISH);
                master.clearActiveTask();
                this.checkTimer = 0;
                this.taskTimer = 0;
                this.chokeTimer = 0;
                this.activeChokeCollar = ItemStack.EMPTY;
                return; // Don't fall through to FOLLOWING
            }
        }

        // Clear task and return to following
        master.clearActiveTask();

        if (master.hasPet()) {
            master.setMasterState(MasterState.FOLLOWING);
        }

        this.checkTimer = 0;
        this.taskTimer = 0;
        this.chokeTimer = 0;
        this.activeChokeCollar = ItemStack.EMPTY;

        TiedUpMod.LOGGER.debug(
            "[MasterTaskWatchGoal] {} stopped watching task (success={})",
            master.getNpcName(),
            success
        );
    }

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

        PetTask task = master.getCurrentTask();
        if (task == null) return;

        // Always look at pet
        master.getLookControl().setLookAt(pet, 30.0F, 30.0F);

        // Increment task timer
        taskTimer++;

        // Handle choke cooldown
        if (chokeTimer > 0) {
            chokeTimer--;
            if (chokeTimer <= 0) {
                deactivateChoke();
            }
        }

        // Show progress every 5 seconds via action bar
        if (
            task.getDurationTicks() > 0 &&
            taskTimer % 100 == 0 &&
            taskTimer >= GRACE_PERIOD
        ) {
            int remainingSec = (task.getDurationTicks() - taskTimer) / 20;
            if (remainingSec > 0) {
                MessageDispatcher.sendActionBar(
                    pet,
                    Component.translatable(
                        "goal.tiedup.master_watch.time_remaining", task.name(), remainingSec
                    ).withStyle(Style.EMPTY.withColor(0xFFAA00))
                );
            }
        }

        // Skip compliance checks during grace period
        if (taskTimer < GRACE_PERIOD) {
            return;
        }

        // Check compliance periodically
        checkTimer++;
        if (checkTimer >= CHECK_INTERVAL) {
            checkTimer = 0;
            checkTaskCompliance(pet, task);
        }
    }

    /**
     * Check if pet is complying with the current task.
     */
    private void checkTaskCompliance(ServerPlayer pet, PetTask task) {
        boolean violation = false;
        String[] violationMessages = null;

        switch (task) {
            case HEEL -> {
                double dist = master.distanceTo(pet);
                if (dist > task.getMaxDistance()) {
                    violation = true;
                    violationMessages = HEEL_VIOLATION_MESSAGES;
                }
            }
            case WAIT_HERE -> {
                Vec3 startPos = master.getTaskStartPosition();
                if (startPos != null) {
                    double dist = pet.position().distanceTo(startPos);
                    if (dist > task.getMaxDistance()) {
                        violation = true;
                        violationMessages = WAIT_VIOLATION_MESSAGES;
                    }
                }
            }
            case KNEEL -> {
                // Must be crouching AND near start position
                if (!pet.isCrouching()) {
                    violation = true;
                    violationMessages = KNEEL_VIOLATION_MESSAGES;
                } else {
                    Vec3 startPos = master.getTaskStartPosition();
                    if (startPos != null) {
                        double dist = pet.position().distanceTo(startPos);
                        if (dist > task.getMaxDistance()) {
                            violation = true;
                            violationMessages = KNEEL_VIOLATION_MESSAGES;
                        }
                    }
                }
            }
            case COME -> {
                // Grace period: only check after half the duration has passed
                double dist = master.distanceTo(pet);
                if (
                    taskTimer > task.getDurationTicks() / 2 &&
                    dist > task.getMaxDistance()
                ) {
                    violation = true;
                    violationMessages = COME_VIOLATION_MESSAGES;
                }
            }
            case PRESENT -> {
                // Must stay near master
                double dist = master.distanceTo(pet);
                if (dist > task.getMaxDistance()) {
                    violation = true;
                    violationMessages = PRESENT_VIOLATION_MESSAGES;
                }
            }
            case SPEAK -> {
                // No continuous check - just late warning at 75% time
                if (
                    taskTimer >= (int) (task.getDurationTicks() * 0.75) &&
                    taskTimer % 60 == 0
                ) {
                    MessageDispatcher.sendChat(
                        pet,
                        Component.translatable(
                            "goal.tiedup.master_watch.speak_waiting", master.getNpcName()
                        ).withStyle(
                            Style.EMPTY.withColor(
                                EntityMaster.MASTER_NAME_COLOR
                            )
                        )
                    );
                }
            }
            case DEMAND -> {
                // No continuous check - just late warning at 60% time (more impatient)
                if (
                    taskTimer >= (int) (task.getDurationTicks() * 0.6) &&
                    taskTimer % 60 == 0
                ) {
                    String[] demandWarnings = {
                        "I said give it to me.",
                        "Don't make me ask again.",
                        "Hand it over. Now.",
                        "*extends hand impatiently*",
                    };
                    String warning = demandWarnings[master
                        .getRandom()
                        .nextInt(demandWarnings.length)];
                    MessageDispatcher.sendChat(
                        pet,
                        Component.translatable(
                            "goal.tiedup.master_watch.demand_warning", master.getNpcName(), warning
                        ).withStyle(
                            Style.EMPTY.withColor(
                                EntityMaster.MASTER_NAME_COLOR
                            )
                        )
                    );
                }
            }
            case DROP -> {
                if (
                    !pet.getMainHandItem().isEmpty() ||
                    !pet.getOffhandItem().isEmpty()
                ) {
                    violation = true;
                    violationMessages = DROP_VIOLATION_MESSAGES;
                }
            }
            case FOLLOW_CLOSE -> {
                double dist = master.distanceTo(pet);
                if (dist > task.getMaxDistance()) {
                    violation = true;
                    violationMessages = FOLLOW_CLOSE_VIOLATION_MESSAGES;
                }
            }
            default -> {
                // Other tasks don't have continuous checks
            }
        }

        if (violation && violationMessages != null) {
            triggerPunishment(pet, violationMessages);
        }
    }

    /**
     * Trigger choke collar punishment for task violation.
     */
    private void triggerPunishment(ServerPlayer pet, String[] messages) {
        // Only punish if not already choking
        if (chokeTimer > 0) return;

        // FIX: Use MessageDispatcher for consistency with earplug system
        String message = messages[master.getRandom().nextInt(messages.length)];
        MessageDispatcher.sendChat(
            pet,
            Component.translatable(
                "goal.tiedup.master_watch.punishment", master.getNpcName(), message
            ).withStyle(Style.EMPTY.withColor(EntityMaster.MASTER_NAME_COLOR))
        );

        // Activate choke collar
        PlayerBindState bindState = PlayerBindState.getInstance(pet);
        if (bindState != null && bindState.hasCollar()) {
            ItemStack collar = bindState.getEquipment(BodyRegionV2.NECK);

            if (CollarHelper.isChokeCollar(collar)) {
                CollarHelper.setChoking(collar, true);
                this.activeChokeCollar = collar;
                this.chokeTimer = CHOKE_DURATION;

                // Play choking sound
                pet
                    .level()
                    .playSound(
                        null,
                        pet.getX(),
                        pet.getY(),
                        pet.getZ(),
                        SoundEvents.PLAYER_HURT,
                        SoundSource.HOSTILE,
                        0.8f,
                        0.5f + master.getRandom().nextFloat() * 0.2f
                    );

                TiedUpMod.LOGGER.debug(
                    "[MasterTaskWatchGoal] {} triggered choke punishment on {}",
                    master.getNpcName(),
                    pet.getName().getString()
                );
            }
        }
    }

    /**
     * Deactivate the choke collar if active.
     */
    private void deactivateChoke() {
        if (
            !activeChokeCollar.isEmpty() &&
            CollarHelper.isChokeCollar(activeChokeCollar)
        ) {
            CollarHelper.setChoking(activeChokeCollar, false);
            TiedUpMod.LOGGER.debug(
                "[MasterTaskWatchGoal] {} deactivated choke",
                master.getNpcName()
            );
        }
        this.activeChokeCollar = ItemStack.EMPTY;
        this.chokeTimer = 0;
    }
}
