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.V2Blocks;
import com.tiedup.remake.v2.blocks.PetBedBlock;
import com.tiedup.remake.v2.blocks.PetBowlBlock;
import com.tiedup.remake.v2.blocks.PetBowlBlockEntity;
import java.util.EnumSet;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;

/**
 * AI Goal for EntityMaster to place Bowl/Bed blocks for pet.
 *
 * This goal is triggered by specific pet needs:
 * - Hungry: Place PET_BOWL, wait for pet to eat, then retrieve
 * - Tired: Place PET_BED, wait for pet to rest, then retrieve
 *
 * The Master places blocks temporarily and retrieves them after use.
 * Can be triggered automatically (pet hunger) or manually via menu.
 *
 * Uses V2 blocks:
 * - Bowl: V2Blocks.PET_BOWL for pet feeding
 * - Bed: V2Blocks.PET_BED for pet sleeping
 */
public class MasterPlaceBlockGoal extends Goal {

    private final EntityMaster master;

    /** Current action being performed */
    private PlaceAction currentAction = PlaceAction.NONE;

    /** Position where block was placed */
    private BlockPos placedBlockPos = null;

    /** Timer for current action */
    private int actionTimer = 0;

    /** Distance to place blocks from pet */
    private static final double PLACE_DISTANCE = 2.0;

    /** Time to wait for pet to use the block (ticks) */
    private static final int USE_WAIT_TIME = 600; // 30 seconds (increased from 10s)

    /** Time to wait before retrieving block (ticks) */
    private static final int RETRIEVE_DELAY = 100; // 5 seconds after use

    private enum PlaceAction {
        NONE,
        PLACING_BOWL, // Walking to place bowl
        WAITING_EAT, // Waiting for pet to eat
        PLACING_PET_BED, // Walking to place pet bed
        WAITING_SLEEP, // Waiting for pet to rest
        RETRIEVING, // Picking up blocks
    }

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

    @Override
    public boolean canUse() {
        // Must have a pet
        if (!master.hasPet()) return false;

        // If an action is triggered manually (via triggerFeeding/triggerResting), always allow
        if (currentAction != PlaceAction.NONE) return true;

        // For automatic triggers, must be in following state
        MasterState state = master.getStateManager().getCurrentState();
        if (state != MasterState.FOLLOWING) return false;

        // Check pet needs (only trigger on actual needs)
        ServerPlayer pet = master.getPetPlayer();
        if (pet == null) return false;

        // Check if pet is hungry (food level < 10)
        if (pet.getFoodData().getFoodLevel() < 10) {
            currentAction = PlaceAction.PLACING_BOWL;
            return true;
        }

        // Check if pet is tired (could check for sleep deprivation effect, etc.)
        // For now, this is disabled - only triggered manually or via events
        // if (isPetTired(pet)) {
        //     currentAction = PlaceAction.PLACING_PET_BED;
        //     return true;
        // }

        return false;
    }

    @Override
    public boolean canContinueToUse() {
        if (!master.hasPet()) return false;
        return currentAction != PlaceAction.NONE;
    }

    @Override
    public void start() {
        this.actionTimer = 0;
        this.placedBlockPos = null;

        ServerPlayer pet = master.getPetPlayer();
        if (pet == null) return;

        // Announce intent based on action
        switch (currentAction) {
            case PLACING_BOWL -> {
                DialogueBridge.talkTo(master, pet, "petplay.feeding");
                TiedUpMod.LOGGER.debug(
                    "[MasterPlaceBlockGoal] {} placing food bowl for {}",
                    master.getNpcName(),
                    pet.getName().getString()
                );
            }
            case PLACING_PET_BED -> {
                DialogueBridge.talkTo(master, pet, "petplay.resting");
                TiedUpMod.LOGGER.debug(
                    "[MasterPlaceBlockGoal] {} placing pet bed for {}",
                    master.getNpcName(),
                    pet.getName().getString()
                );
            }
            default -> {
            }
        }
    }

    @Override
    public void stop() {
        // Cleanup - retrieve any placed blocks
        if (
            placedBlockPos != null &&
            master.level() instanceof ServerLevel serverLevel
        ) {
            serverLevel.setBlock(
                placedBlockPos,
                Blocks.AIR.defaultBlockState(),
                3
            );
            placedBlockPos = null;
        }

        this.currentAction = PlaceAction.NONE;
        this.actionTimer = 0;
    }

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

        actionTimer++;

        switch (currentAction) {
            case PLACING_BOWL -> tickPlacingBowl(pet);
            case WAITING_EAT -> tickWaitingEat(pet);
            case PLACING_PET_BED -> tickPlacingPetBed(pet);
            case WAITING_SLEEP -> tickWaitingSleep(pet);
            case RETRIEVING -> tickRetrieving();
            default -> {
            }
        }
    }

    private void tickPlacingBowl(ServerPlayer pet) {
        // Move near pet
        double distSq = master.distanceToSqr(pet);
        if (distSq > PLACE_DISTANCE * PLACE_DISTANCE + 4) {
            master.getNavigation().moveTo(pet, 1.0);
            return;
        }

        master.getNavigation().stop();

        // Find placement position and place bowl (facing toward the pet)
        BlockPos pos = findPlacementPos(pet);
        Direction facing = Direction.fromYRot(master.getYRot()).getOpposite();
        BlockState bowlState = V2Blocks.PET_BOWL.get()
            .defaultBlockState()
            .setValue(PetBowlBlock.FACING, facing);
        if (pos != null && placeBlock(pos, bowlState)) {
            placedBlockPos = pos;
            currentAction = PlaceAction.WAITING_EAT;
            actionTimer = 0;

            // Fill the bowl with food (20 = full)
            if (master.level() instanceof ServerLevel serverLevel) {
                if (
                    serverLevel.getBlockEntity(pos) instanceof
                        PetBowlBlockEntity bowl
                ) {
                    bowl.fillBowl(20);
                }
            }

            // Tell pet to eat
            DialogueBridge.talkTo(master, pet, "petplay.eat_command");

            TiedUpMod.LOGGER.debug(
                "[MasterPlaceBlockGoal] {} placed food bowl at {}",
                master.getNpcName(),
                pos
            );
        } else {
            // Can't place, abort
            TiedUpMod.LOGGER.warn(
                "[MasterPlaceBlockGoal] {} couldn't find place for bowl",
                master.getNpcName()
            );
            currentAction = PlaceAction.NONE;
        }
    }

    private void tickWaitingEat(ServerPlayer pet) {
        // Look at pet
        master.getLookControl().setLookAt(pet, 30.0F, 30.0F);

        // Check if pet has eaten (food level restored)
        if (pet.getFoodData().getFoodLevel() >= 16) {
            // Pet finished eating
            DialogueBridge.talkTo(master, pet, "petplay.good_pet");
            currentAction = PlaceAction.RETRIEVING;
            actionTimer = 0;
            return;
        }

        // Timeout - pet didn't eat
        if (actionTimer > USE_WAIT_TIME) {
            DialogueBridge.talkTo(master, pet, "petplay.disappointed");
            currentAction = PlaceAction.RETRIEVING;
            actionTimer = 0;
        }
    }

    private void tickPlacingPetBed(ServerPlayer pet) {
        // Move near pet
        double distSq = master.distanceToSqr(pet);
        if (distSq > PLACE_DISTANCE * PLACE_DISTANCE + 4) {
            master.getNavigation().moveTo(pet, 1.0);
            return;
        }

        master.getNavigation().stop();

        // Find placement position and place bed (facing toward the pet)
        BlockPos pos = findPlacementPos(pet);
        Direction facing = Direction.fromYRot(master.getYRot()).getOpposite();
        BlockState bedState = V2Blocks.PET_BED.get()
            .defaultBlockState()
            .setValue(PetBedBlock.FACING, facing);
        if (pos != null && placeBlock(pos, bedState)) {
            placedBlockPos = pos;
            currentAction = PlaceAction.WAITING_SLEEP;
            actionTimer = 0;

            // Tell pet to rest
            DialogueBridge.talkTo(master, pet, "petplay.rest_command");

            TiedUpMod.LOGGER.debug(
                "[MasterPlaceBlockGoal] {} placed pet bed at {}",
                master.getNpcName(),
                pos
            );
        } else {
            // Can't place, abort
            currentAction = PlaceAction.NONE;
        }
    }

    private void tickWaitingSleep(ServerPlayer pet) {
        // Look at pet
        master.getLookControl().setLookAt(pet, 30.0F, 30.0F);

        // FIX: Check if pet is currently sleeping
        if (pet.isSleeping()) {
            // Pet is sleeping - reset timer to let them sleep as long as they want
            // Only start counting down after they wake up
            actionTimer = 0;
            return;
        }

        // Pet is not sleeping (either hasn't started or has woken up)
        // Timeout - retrieve pet bed after some time of NOT sleeping
        if (actionTimer > USE_WAIT_TIME) {
            DialogueBridge.talkTo(master, pet, "petplay.wake_up");
            currentAction = PlaceAction.RETRIEVING;
            actionTimer = 0;
        }
    }

    private void tickRetrieving() {
        if (actionTimer > RETRIEVE_DELAY) {
            // FIX: Safety check - don't remove block if pet is still sleeping
            ServerPlayer pet = master.getPetPlayer();
            if (pet != null && pet.isSleeping()) {
                // Pet is still sleeping - wait for them to wake up
                actionTimer = 0; // Reset timer
                return;
            }

            // Remove the placed block
            if (
                placedBlockPos != null &&
                master.level() instanceof ServerLevel serverLevel
            ) {
                serverLevel.setBlock(
                    placedBlockPos,
                    Blocks.AIR.defaultBlockState(),
                    3
                );

                TiedUpMod.LOGGER.debug(
                    "[MasterPlaceBlockGoal] {} retrieved block at {}",
                    master.getNpcName(),
                    placedBlockPos
                );

                placedBlockPos = null;
            }

            // Done with this action
            currentAction = PlaceAction.NONE;
        }
    }

    /**
     * Find a suitable position to place a block near the pet.
     */
    private BlockPos findPlacementPos(ServerPlayer pet) {
        BlockPos petPos = pet.blockPosition();

        // Search for valid placement nearby
        for (int dx = -2; dx <= 2; dx++) {
            for (int dz = -2; dz <= 2; dz++) {
                if (dx == 0 && dz == 0) continue; // Not on pet

                BlockPos pos = petPos.offset(dx, 0, dz);
                if (isValidPlacement(pos)) {
                    return pos;
                }

                // Try one block lower
                BlockPos lower = pos.below();
                if (isValidPlacement(lower)) {
                    return lower;
                }
            }
        }

        return null;
    }

    /**
     * Check if position is valid for block placement.
     */
    private boolean isValidPlacement(BlockPos pos) {
        BlockState below = master.level().getBlockState(pos.below());
        BlockState at = master.level().getBlockState(pos);

        return below.isSolidRender(master.level(), pos.below()) && at.isAir();
    }

    /**
     * Place a block at the given position.
     */
    private boolean placeBlock(BlockPos pos, BlockState state) {
        if (!(master.level() instanceof ServerLevel serverLevel)) {
            return false;
        }

        serverLevel.setBlock(pos, state, 3);
        return true;
    }

    /**
     * Manually trigger feeding action (called from events/commands).
     */
    public void triggerFeeding() {
        if (currentAction == PlaceAction.NONE && master.hasPet()) {
            currentAction = PlaceAction.PLACING_BOWL;
        }
    }

    /**
     * Manually trigger resting action (called from events/commands).
     */
    public void triggerResting() {
        if (currentAction == PlaceAction.NONE && master.hasPet()) {
            currentAction = PlaceAction.PLACING_PET_BED;
        }
    }

    // FIX: NBT PERSISTENCE FOR PLACED BLOCKS

    /**
     * Get the currently placed block position (for NBT saving).
     */
    public BlockPos getPlacedBlockPos() {
        return placedBlockPos;
    }

    /**
     * Set the placed block position (for NBT loading).
     * Also cleans up the block if position is set on load.
     */
    public void setPlacedBlockPos(BlockPos pos) {
        this.placedBlockPos = pos;
    }

    /**
     * Cleanup orphaned blocks after entity load.
     * Called from EntityMaster after loading NBT if a position was saved.
     */
    public void cleanupOrphanedBlock() {
        if (
            placedBlockPos != null &&
            master.level() instanceof ServerLevel serverLevel
        ) {
            BlockState state = serverLevel.getBlockState(placedBlockPos);
            // Only remove if it's one of our V2 pet blocks
            if (
                state.is(V2Blocks.PET_BOWL.get()) ||
                state.is(V2Blocks.PET_BED.get())
            ) {
                serverLevel.setBlock(
                    placedBlockPos,
                    Blocks.AIR.defaultBlockState(),
                    3
                );
                TiedUpMod.LOGGER.info(
                    "[MasterPlaceBlockGoal] {} cleaned up orphaned block at {}",
                    master.getNpcName(),
                    placedBlockPos
                );
            }
            placedBlockPos = null;
        }
    }
}
