package com.tiedup.remake.entities.ai.maid.goals;

import com.tiedup.remake.cells.CellDataV2;
import com.tiedup.remake.cells.CellRegistryV2;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityMaid;
import com.tiedup.remake.entities.EntitySlaveTrader;
import com.tiedup.remake.labor.LaborTask;
import com.tiedup.remake.prison.LaborRecord;
import com.tiedup.remake.prison.PrisonerManager;
import com.tiedup.remake.prison.PrisonerState;
import java.util.*;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.ai.goal.Goal;

/**
 * Goal: Idle behavior and work monitoring.
 *
 * Responsibilities:
 * - Monitor working prisoners for task completion
 * - Check for task timeouts and failures
 * - Patrol cells when idle
 * - Stay near trader when nothing to do
 */
public class MaidIdleGoal extends Goal {

    private static final int MONITOR_INTERVAL_TICKS = 100; // 5 seconds
    private static final int PATROL_INTERVAL_TICKS = 1200; // 1 minute
    private static final double TRADER_FOLLOW_DISTANCE = 10.0;

    private final EntityMaid maid;
    private final Random random = new Random();

    private int monitorCounter = 0;
    private int patrolCounter = 0;
    private BlockPos patrolTarget;
    private boolean isPatrolling;

    public MaidIdleGoal(EntityMaid maid) {
        this.maid = maid;
        this.setFlags(EnumSet.of(Flag.MOVE));
    }

    @Override
    public boolean canUse() {
        if (maid.isFreed() || maid.isTiedUp()) {
            return false;
        }
        if (maid.getMaidState().isBusy()) {
            return false;
        }
        return true;
    }

    @Override
    public void tick() {
        monitorCounter++;
        patrolCounter++;

        if (!(maid.level() instanceof ServerLevel level)) {
            return;
        }

        // Monitor working prisoners
        if (monitorCounter >= MONITOR_INTERVAL_TICKS) {
            monitorCounter = 0;
            monitorWorkers(level);
        }

        // Patrol or follow trader
        if (isPatrolling) {
            tickPatrol(level);
        } else if (patrolCounter >= PATROL_INTERVAL_TICKS) {
            patrolCounter = 0;
            maybeStartPatrol(level);
        } else {
            followTrader();
        }
    }

    /**
     * Monitor working prisoners for task completion.
     */
    private void monitorWorkers(ServerLevel level) {
        UUID campId = maid.getCampUUID();
        if (campId == null) {
            return;
        }

        PrisonerManager manager = PrisonerManager.get(level);
        long currentTime = level.getGameTime();

        Set<UUID> workers = manager.getPrisonersInCampWithState(
            campId,
            PrisonerState.WORKING
        );

        for (UUID prisonerId : workers) {
            LaborRecord labor = manager.getLaborRecord(prisonerId);

            // Only monitor WORKING phase
            if (labor.getPhase() != LaborRecord.WorkPhase.WORKING) {
                continue;
            }

            // Skip prisoners with an active guard (guard handles monitoring)
            // BUT verify the guard entity actually exists - if it disappeared
            // without cleanup (crash, chunk corruption), clear the stale reference
            if (labor.getGuardId() != null) {
                net.minecraft.world.entity.Entity guardEntity = level.getEntity(
                    labor.getGuardId()
                );
                if (guardEntity != null && guardEntity.isAlive()) {
                    continue; // Guard is alive, it handles monitoring
                }
                // Guard is gone - clear stale reference so maid takes over
                TiedUpMod.LOGGER.warn(
                    "[MaidIdleGoal] Guard {} for prisoner {} is missing/dead - clearing stale reference",
                    labor.getGuardId().toString().substring(0, 8),
                    prisonerId.toString().substring(0, 8)
                );
                labor.setGuardId(null);
                manager.markDirty();
            }

            ServerPlayer prisoner = level
                .getServer()
                .getPlayerList()
                .getPlayer(prisonerId);
            if (prisoner == null) {
                continue;
            }

            LaborTask task = labor.getTask();
            if (task == null) {
                continue;
            }

            // Check task progress
            task.checkProgress(prisoner, level);

            if (task.isComplete()) {
                // Task complete - trigger return
                labor.completeTask(currentTime);

                prisoner.sendSystemMessage(
                    net.minecraft.network.chat.Component.translatable(
                        "goal.tiedup.maid_idle.task_complete"
                    ).withStyle(net.minecraft.ChatFormatting.GREEN)
                );

                TiedUpMod.LOGGER.info(
                    "[MaidIdleGoal] {} completed task",
                    prisoner.getName().getString()
                );
            } else {
                // Check for inactivity
                checkActivity(prisoner, labor, currentTime);
            }
        }
    }

    /**
     * Check prisoner activity and punish inactivity.
     */
    private void checkActivity(
        ServerPlayer prisoner,
        LaborRecord labor,
        long currentTime
    ) {
        BlockPos currentPos = prisoner.blockPosition();
        boolean hasMoved = labor.hasMovedFrom(
            currentPos.getX(),
            currentPos.getY(),
            currentPos.getZ(),
            2 // 2 block threshold
        );

        if (hasMoved) {
            // Active - update position and reset inactivity
            labor.updateActivity(
                currentTime,
                currentPos.getX(),
                currentPos.getY(),
                currentPos.getZ()
            );
            labor.resetShockLevel();
        } else {
            // Inactive - check time
            long inactiveTime = currentTime - labor.getLastActivityTime();
            long inactiveThreshold = 600; // 30 seconds

            if (inactiveTime > inactiveThreshold) {
                // Punish inactivity
                labor.incrementShockLevel();
                labor.updateActivity(
                    currentTime,
                    currentPos.getX(),
                    currentPos.getY(),
                    currentPos.getZ()
                );

                int shockLevel = labor.getShockLevel();
                if (shockLevel >= 3) {
                    // Max punishment - fail task
                    labor.failTask(currentTime);
                    prisoner.sendSystemMessage(
                        net.minecraft.network.chat.Component.translatable(
                            "goal.tiedup.maid_idle.task_failed"
                        ).withStyle(net.minecraft.ChatFormatting.RED)
                    );
                } else {
                    // Warning
                    prisoner.sendSystemMessage(
                        net.minecraft.network.chat.Component.translatable(
                            "goal.tiedup.maid_idle.inactivity_warning",
                            shockLevel
                        ).withStyle(net.minecraft.ChatFormatting.YELLOW)
                    );

                    // Shock the prisoner
                    var cap =
                        com.tiedup.remake.util.KidnappedHelper.getKidnappedState(
                            prisoner
                        );
                    if (cap != null) {
                        cap.shockKidnapped("Get back to work!", shockLevel);
                    }
                }
            }
        }
    }

    /**
     * Maybe start a patrol.
     */
    private void maybeStartPatrol(ServerLevel level) {
        // 20% chance to patrol
        if (random.nextFloat() > 0.2f) {
            return;
        }

        UUID campId = maid.getCampUUID();
        if (campId == null) {
            return;
        }

        // Get camp cells
        CellRegistryV2 registry = CellRegistryV2.get(level);
        List<CellDataV2> cells = registry.getCellsByCamp(campId);

        if (cells.isEmpty()) {
            return;
        }

        // Pick a random cell to check
        CellDataV2 targetCell = cells.get(random.nextInt(cells.size()));
        patrolTarget = targetCell.getCorePos();
        isPatrolling = true;

        TiedUpMod.LOGGER.debug("[MaidIdleGoal] Starting patrol to cell");
    }

    /**
     * Tick patrol behavior.
     */
    private void tickPatrol(ServerLevel level) {
        if (patrolTarget == null) {
            isPatrolling = false;
            return;
        }

        // Navigate to target
        if (maid.getNavigation().isDone()) {
            maid
                .getNavigation()
                .moveTo(
                    patrolTarget.getX() + 0.5,
                    patrolTarget.getY(),
                    patrolTarget.getZ() + 0.5,
                    0.8
                );
        }

        // Check if arrived
        double distance = maid
            .position()
            .distanceTo(
                new net.minecraft.world.phys.Vec3(
                    patrolTarget.getX() + 0.5,
                    patrolTarget.getY(),
                    patrolTarget.getZ() + 0.5
                )
            );

        if (distance < 3.0) {
            // Arrived - done patrolling
            isPatrolling = false;
            patrolTarget = null;
            TiedUpMod.LOGGER.debug("[MaidIdleGoal] Patrol complete");
        }
    }

    /**
     * Follow the trader when idle.
     */
    private void followTrader() {
        EntitySlaveTrader trader = maid.getMasterTrader();
        if (trader == null) {
            return;
        }

        double distance = maid.distanceTo(trader);
        if (distance > TRADER_FOLLOW_DISTANCE) {
            maid.getNavigation().moveTo(trader, 0.6);
        }
    }

    @Override
    public boolean canContinueToUse() {
        return canUse();
    }

    @Override
    public void stop() {
        isPatrolling = false;
        patrolTarget = null;
    }
}
