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

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.dialogue.EntityDialogueManager.DialogueCategory;
import com.tiedup.remake.entities.EntityKidnapper;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.util.RestraintApplicator;
import java.util.EnumSet;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.goal.Goal;

/**
 * AI Goal for EntityKidnapper to punish a recaptured prisoner.
 *
 *
 * This goal:
 * 1. Activates when kidnapper is in PUNISH state with a captive
 * 2. Tightens binds (resets resistance to max)
 * 3. Adds gag if missing
 * 4. Adds blindfold on repeat escapes
 * 5. Resets struggle progress
 * 6. Sends intimidating message
 * 7. Duration: 5-10 seconds
 */
public class KidnapperPunishGoal extends Goal {

    private final EntityKidnapper kidnapper;

    /** Minimum punishment duration (30 seconds = 600 ticks) */
    private static final int MIN_PUNISH_DURATION = 600;

    /** Maximum punishment duration (90 seconds = 1800 ticks) */
    private static final int MAX_PUNISH_DURATION = 1800;

    /** Dialogue radius */
    private static final int DIALOGUE_RADIUS = 20;

    /** Ticks between punishment actions */
    private static final int ACTION_INTERVAL = 40; // 2 seconds

    /** The captive being punished */
    private IBondageState captive;

    /** Ticks spent punishing */
    private int punishTicks;

    /** Duration of this punishment session */
    private int punishDuration;

    /** Track which actions have been performed */
    private boolean tightenedBinds = false;
    private boolean addedGag = false;
    private boolean addedBlindfold = false;

    public KidnapperPunishGoal(EntityKidnapper kidnapper) {
        this.kidnapper = kidnapper;
        this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
    }

    @Override
    public boolean canUse() {
        // Must be in PUNISH state
        if (this.kidnapper.getCurrentState() != KidnapperState.PUNISH) {
            return false;
        }

        // Must have a captive
        if (!this.kidnapper.hasCaptives()) {
            return false;
        }

        // Must not be tied up
        if (this.kidnapper.isTiedUp()) {
            return false;
        }

        this.captive = this.kidnapper.getCaptive();
        return this.captive != null;
    }

    @Override
    public boolean canContinueToUse() {
        if (this.kidnapper.isTiedUp()) {
            return false;
        }

        if (!this.kidnapper.hasCaptives() || this.captive == null) {
            return false;
        }

        // Stop when punishment duration complete
        if (this.punishTicks >= this.punishDuration) {
            return false;
        }

        return this.kidnapper.getCurrentState() == KidnapperState.PUNISH;
    }

    @Override
    public void start() {
        this.punishTicks = 0;
        this.tightenedBinds = false;
        this.addedGag = false;
        this.addedBlindfold = false;

        // Random punishment duration
        this.punishDuration =
            MIN_PUNISH_DURATION +
            this.kidnapper.getRandom().nextInt(
                MAX_PUNISH_DURATION - MIN_PUNISH_DURATION
            );

        // Stop navigation - stay in place
        this.kidnapper.getNavigation().stop();

        // Announce punishment
        this.kidnapper.talkToPlayersInRadius(
            DialogueCategory.PUNISH,
            DIALOGUE_RADIUS
        );

        TiedUpMod.LOGGER.info(
            "[KidnapperPunishGoal] {} started punishing {} for {} ticks",
            this.kidnapper.getNpcName(),
            this.captive.getKidnappedName(),
            this.punishDuration
        );
    }

    @Override
    public void stop() {
        // MEDIUM FIX: Validate before transitioning to TRANSPORT
        // Without these checks, we could transition to TRANSPORT with no captive or dead camp,
        // causing a deadlock where BringToCellGoal activates but has nothing to transport
        if (this.kidnapper.getCurrentState() == KidnapperState.PUNISH) {
            // Only transition to TRANSPORT if we still have a captive
            if (this.kidnapper.hasCaptives()) {
                // If this is a camp kidnapper, validate the camp is still alive
                java.util.UUID campId = this.kidnapper.getAssociatedStructure();
                if (campId != null) {
                    // Camp kidnapper - check if camp still exists
                    if (
                        this.kidnapper.level() instanceof
                            net.minecraft.server.level.ServerLevel serverLevel
                    ) {
                        com.tiedup.remake.cells.CampOwnership ownership =
                            com.tiedup.remake.cells.CampOwnership.get(
                                serverLevel
                            );
                        com.tiedup.remake.cells.CampOwnership.CampData campData =
                            ownership.getCamp(campId);

                        if (campData != null && campData.isAlive()) {
                            // Camp is alive - safe to transport
                            this.kidnapper.setCurrentState(
                                KidnapperState.TRANSPORT
                            );
                        } else {
                            // Camp is dead - release captive and return to idle
                            TiedUpMod.LOGGER.warn(
                                "[KidnapperPunishGoal] {} camp is dead, releasing captive instead of transporting",
                                this.kidnapper.getNpcName()
                            );
                            this.kidnapper.abandonCaptive();
                            this.kidnapper.setCurrentState(KidnapperState.IDLE);
                        }
                    } else {
                        // Client side or invalid level - default to transport
                        this.kidnapper.setCurrentState(
                            KidnapperState.TRANSPORT
                        );
                    }
                } else {
                    // Wild kidnapper - always safe to transport
                    this.kidnapper.setCurrentState(KidnapperState.TRANSPORT);
                }
            } else {
                // No captive - return to idle
                TiedUpMod.LOGGER.warn(
                    "[KidnapperPunishGoal] {} lost captive during punishment, returning to idle",
                    this.kidnapper.getNpcName()
                );
                this.kidnapper.setCurrentState(KidnapperState.IDLE);
            }
        }

        TiedUpMod.LOGGER.info(
            "[KidnapperPunishGoal] {} finished punishing {}",
            this.kidnapper.getNpcName(),
            this.captive != null ? this.captive.getKidnappedName() : "unknown"
        );

        this.captive = null;
        this.punishTicks = 0;
    }

    @Override
    public void tick() {
        if (this.captive == null) {
            return;
        }

        this.punishTicks++;

        // Look at the captive
        LivingEntity captiveEntity = this.captive.asLivingEntity();
        if (captiveEntity != null) {
            this.kidnapper.getLookControl().setLookAt(
                captiveEntity,
                30.0F,
                30.0F
            );
        }

        // Perform punishment actions at intervals
        if (this.punishTicks % ACTION_INTERVAL == 0) {
            performPunishmentAction();
        }
    }

    /**
     * Perform the next punishment action in sequence.
     */
    private void performPunishmentAction() {
        // Action 1: Tighten binds (reset resistance to max)
        if (!this.tightenedBinds) {
            tightenBinds();
            this.tightenedBinds = true;
            return;
        }

        // Action 2: Add gag if missing
        if (!this.addedGag) {
            addGagIfMissing();
            this.addedGag = true;
            return;
        }

        // Action 3: Add blindfold (for repeat escapes - check if already gagged means this is serious)
        if (!this.addedBlindfold) {
            addBlindfoldIfWarranted();
            this.addedBlindfold = true;
            return;
        }
    }

    /**
     * Tighten the captive's binds by resetting resistance to maximum.
     */
    private void tightenBinds() {
        LivingEntity captiveEntity = this.captive.asLivingEntity();
        if (
            RestraintApplicator.applyOrTightenBind(
                captiveEntity,
                this.kidnapper.getBindItem()
            )
        ) {
            TiedUpMod.LOGGER.debug(
                "[KidnapperPunishGoal] Tightened/applied binds on {}",
                this.captive.getKidnappedName()
            );
        }
    }

    /**
     * Add a gag if the captive doesn't have one.
     */
    private void addGagIfMissing() {
        LivingEntity captiveEntity = this.captive.asLivingEntity();
        if (
            RestraintApplicator.applyGagIfMissing(
                captiveEntity,
                this.kidnapper.getGagItem()
            )
        ) {
            TiedUpMod.LOGGER.debug(
                "[KidnapperPunishGoal] Applied gag to {}",
                this.captive.getKidnappedName()
            );
        }
    }

    /**
     * Add a blindfold if warranted (repeat escape or already has other accessories).
     */
    private void addBlindfoldIfWarranted() {
        LivingEntity captiveEntity = this.captive.asLivingEntity();
        if (
            RestraintApplicator.applyBlindfoldIfMissing(
                captiveEntity,
                this.kidnapper.getBlindfoldItem()
            )
        ) {
            TiedUpMod.LOGGER.debug(
                "[KidnapperPunishGoal] Applied blindfold to {}",
                this.captive.getKidnappedName()
            );
        }
    }

    @Override
    public boolean requiresUpdateEveryTick() {
        return false;
    }
}
