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

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.ai.master.MasterState;
import java.util.Random;
import java.util.UUID;
import net.minecraft.server.level.ServerPlayer;

/**
 * MasterStateManager - Manages the behavioral state of a Master entity.
 *
 * Features:
 * - State transitions with debug logging
 * - Distraction timer system (30-60 sec every 2-5 min)
 * - Struggle detection during watching states
 * - Pet player tracking
 */
public class MasterStateManager {

    // CONSTANTS

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

    /** Maximum time between distractions (ticks) - 5 minutes */
    private static final int MAX_DISTRACTION_INTERVAL = 6000;

    /** Minimum distraction duration (ticks) - 30 seconds */
    private static final int MIN_DISTRACTION_DURATION = 600;

    /** Maximum distraction duration (ticks) - 60 seconds */
    private static final int MAX_DISTRACTION_DURATION = 1200;

    // FIELDS

    /** Host callbacks for logging and events */
    private final IMasterStateHost host;

    /** Current behavioral state */
    private MasterState currentState = MasterState.IDLE;

    /** Previous state (for returning after distraction) */
    private MasterState previousState = MasterState.IDLE;

    /** UUID of the pet player owned by this master */
    private UUID petPlayerUUID = null;

    /** Tick when next distraction will occur */
    private long nextDistractionTick = 0;

    /** Tick when current distraction will end */
    private long distractionEndTick = 0;

    /** Whether distraction timer has been initialized */
    private boolean distractionInitialized = false;

    /** Random for distraction timing */
    private final Random random = new Random();

    // CONSTRUCTOR

    public MasterStateManager(IMasterStateHost host) {
        this.host = host;
    }

    // STATE MANAGEMENT

    /**
     * Get the current behavioral state.
     *
     * @return The current state
     */
    public MasterState getCurrentState() {
        return this.currentState;
    }

    /**
     * Set the current behavioral state with debug logging.
     *
     * @param state The new state
     */
    public void setCurrentState(MasterState state) {
        if (this.currentState != state) {
            TiedUpMod.LOGGER.debug(
                "[MasterStateManager] {} state change: {} -> {}",
                host.getNpcName(),
                this.currentState,
                state
            );
            this.previousState = this.currentState;
            this.currentState = state;
        }
    }

    /**
     * Check if master is currently watching the pet.
     * In watching states, struggle attempts will be detected.
     *
     * @return true if master can see struggle attempts
     */
    public boolean isWatching() {
        return currentState.isWatching() || currentState.canDetectStruggle();
    }

    /**
     * Check if pet can safely struggle without detection.
     *
     * @return true if master is distracted or idle
     */
    public boolean canPetStruggleSafely() {
        return currentState.allowsSafeStruggle();
    }

    // PET PLAYER MANAGEMENT

    /**
     * Set the UUID of the pet player owned by this master.
     *
     * @param playerUUID The pet player's UUID
     */
    public void setPetPlayerUUID(UUID playerUUID) {
        this.petPlayerUUID = playerUUID;
        TiedUpMod.LOGGER.info(
            "[MasterStateManager] {} now owns pet {}",
            host.getNpcName(),
            playerUUID
        );
    }

    /**
     * Get the UUID of the pet player.
     *
     * @return Pet player UUID or null if none
     */
    public UUID getPetPlayerUUID() {
        return this.petPlayerUUID;
    }

    /**
     * Check if this master has a pet.
     *
     * @return true if master has a pet player
     */
    public boolean hasPet() {
        return this.petPlayerUUID != null;
    }

    /**
     * Clear the pet player (on death, escape, etc.)
     */
    public void clearPet() {
        TiedUpMod.LOGGER.info(
            "[MasterStateManager] {} lost pet {}",
            host.getNpcName(),
            this.petPlayerUUID
        );
        this.petPlayerUUID = null;
    }

    // DISTRACTION SYSTEM

    /**
     * Initialize or reset the distraction timer.
     * Should be called when master starts following pet.
     */
    public void initializeDistractionTimer() {
        long currentTick = host.getCurrentTick();
        int interval =
            MIN_DISTRACTION_INTERVAL +
            random.nextInt(MAX_DISTRACTION_INTERVAL - MIN_DISTRACTION_INTERVAL);
        this.nextDistractionTick = currentTick + interval;
        this.distractionInitialized = true;

        TiedUpMod.LOGGER.debug(
            "[MasterStateManager] {} distraction timer set for {} ticks ({}s)",
            host.getNpcName(),
            interval,
            interval / 20
        );
    }

    /**
     * Tick the distraction system.
     * Should be called every server tick.
     *
     * @return true if a state change occurred
     */
    public boolean tickDistraction() {
        if (!distractionInitialized || petPlayerUUID == null) {
            return false;
        }

        long currentTick = host.getCurrentTick();

        // Check if currently distracted
        if (currentState == MasterState.DISTRACTED) {
            // Check if distraction should end
            if (currentTick >= distractionEndTick) {
                endDistraction();
                return true;
            }
            return false;
        }

        // Check if should become distracted
        if (
            currentTick >= nextDistractionTick &&
            currentState.canTransitionToPunish()
        ) {
            startDistraction();
            return true;
        }

        return false;
    }

    /**
     * Start a distraction period.
     */
    private void startDistraction() {
        long currentTick = host.getCurrentTick();
        int duration =
            MIN_DISTRACTION_DURATION +
            random.nextInt(MAX_DISTRACTION_DURATION - MIN_DISTRACTION_DURATION);

        this.previousState = this.currentState;
        this.distractionEndTick = currentTick + duration;
        setCurrentState(MasterState.DISTRACTED);

        TiedUpMod.LOGGER.info(
            "[MasterStateManager] {} became distracted for {}s",
            host.getNpcName(),
            duration / 20
        );

        host.onDistracted();
    }

    /**
     * End the current distraction and return to previous state.
     */
    private void endDistraction() {
        TiedUpMod.LOGGER.info(
            "[MasterStateManager] {} distraction ended, returning to {}",
            host.getNpcName(),
            previousState
        );

        // Schedule next distraction
        long currentTick = host.getCurrentTick();
        int interval =
            MIN_DISTRACTION_INTERVAL +
            random.nextInt(MAX_DISTRACTION_INTERVAL - MIN_DISTRACTION_INTERVAL);
        this.nextDistractionTick = currentTick + interval;

        // Return to previous state (or FOLLOWING if previous was IDLE)
        MasterState returnState =
            previousState == MasterState.IDLE
                ? MasterState.FOLLOWING
                : previousState;
        setCurrentState(returnState);

        host.onDistractionEnd();
    }

    /**
     * Get remaining ticks until distraction ends.
     * Returns 0 if not currently distracted.
     *
     * @return Remaining ticks or 0
     */
    public long getRemainingDistractionTicks() {
        if (currentState != MasterState.DISTRACTED) {
            return 0;
        }
        long remaining = distractionEndTick - host.getCurrentTick();
        return Math.max(0, remaining);
    }

    /**
     * Force distraction to end early (e.g., if attacked).
     */
    public void interruptDistraction() {
        if (currentState == MasterState.DISTRACTED) {
            TiedUpMod.LOGGER.info(
                "[MasterStateManager] {} distraction interrupted!",
                host.getNpcName()
            );
            endDistraction();
        }
    }

    // STRUGGLE DETECTION

    /**
     * Called when a struggle attempt is detected.
     * Will transition to PUNISH state if master was watching.
     *
     * @return true if struggle was detected (master was watching)
     */
    public boolean onStruggleAttempt() {
        if (!isWatching()) {
            return false; // Struggle not detected
        }

        TiedUpMod.LOGGER.info(
            "[MasterStateManager] {} detected struggle attempt!",
            host.getNpcName()
        );

        // Transition to punish state
        if (currentState.canTransitionToPunish()) {
            setCurrentState(MasterState.PUNISH);
        }

        host.onStruggleDetected();
        return true;
    }

    // NBT SERIALIZATION

    /**
     * Get the state name for NBT serialization.
     *
     * @return The state name as a string
     */
    public String serializeState() {
        return currentState.name();
    }

    /**
     * Deserialize state from NBT.
     *
     * @param stateName The state name string
     */
    public void deserializeState(String stateName) {
        try {
            this.currentState = MasterState.valueOf(stateName);
        } catch (IllegalArgumentException e) {
            TiedUpMod.LOGGER.warn(
                "[MasterStateManager] Invalid state name: {}, defaulting to IDLE",
                stateName
            );
            this.currentState = MasterState.IDLE;
        }
    }

    /**
     * Serialize pet UUID for NBT.
     *
     * @return UUID string or null
     */
    public String serializePetUUID() {
        return petPlayerUUID != null ? petPlayerUUID.toString() : null;
    }

    /**
     * Deserialize pet UUID from NBT.
     *
     * @param uuidString UUID string or null
     */
    public void deserializePetUUID(String uuidString) {
        if (uuidString != null && !uuidString.isEmpty()) {
            try {
                this.petPlayerUUID = UUID.fromString(uuidString);
            } catch (IllegalArgumentException e) {
                TiedUpMod.LOGGER.warn(
                    "[MasterStateManager] Invalid pet UUID: {}",
                    uuidString
                );
                this.petPlayerUUID = null;
            }
        } else {
            this.petPlayerUUID = null;
        }
    }
}
