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

import com.tiedup.remake.entities.EntityDamsel;
import com.tiedup.remake.personality.NpcCommand;
import com.tiedup.remake.personality.PersonalityState;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.*;
import net.minecraft.world.level.block.state.BlockState;

/**
 * AI Goal: NPC farms crops in a zone around a chest hub.
 *
 * <p><b>Chest-Hub System:</b></p>
 * <ul>
 *   <li>Chest position defines the work zone center (radius 8)</li>
 *   <li>Chest provides seeds for replanting</li>
 *   <li>Harvested crops are stored in the chest</li>
 * </ul>
 *
 * <p><b>Behavior:</b></p>
 * <ul>
 *   <li>Scans zone for mature crops</li>
 *   <li>Harvests mature crops</li>
 *   <li>Replants using seeds from drops or chest</li>
 *   <li>Stores harvest in chest</li>
 *   <li>Awards XP periodically</li>
 * </ul>
 */
public class NpcFarmCommandGoal extends AbstractNpcJobGoal {

    /** Distance to interact with block */
    private static final double INTERACT_DISTANCE = 2.0;

    /** Rest drain intensity for farming (medium work) */
    private static final float WORK_INTENSITY = 1.0f;

    /** Minimum cooldown for job idle dialogue (30 sec) */
    private static final int JOB_IDLE_TALK_MIN = 600;

    /** Maximum cooldown for job idle dialogue (1.5 min) */
    private static final int JOB_IDLE_TALK_MAX = 1800;

    // Job-specific phases
    private static final int PHASE_MOVING = PHASE_JOB_SPECIFIC;
    private static final int PHASE_HARVESTING = PHASE_JOB_SPECIFIC + 1;

    @Nullable
    private BlockPos targetCrop;

    private int harvestCooldown;
    private int jobIdleTalkCooldown;

    public NpcFarmCommandGoal(EntityDamsel npc, double speedModifier) {
        super(npc, speedModifier);
    }

    // ==================== Abstract Implementations ====================

    @Override
    protected NpcCommand getCommand() {
        return NpcCommand.FARM;
    }

    @Override
    @Nullable
    protected BlockPos findWorkTarget() {
        return findMatureCropInZone();
    }

    @Override
    protected void onWorkTargetFound(BlockPos target) {
        this.targetCrop = target;
        this.phase = PHASE_MOVING;
    }

    @Override
    protected void onStart() {
        this.harvestCooldown = 0;
        this.jobIdleTalkCooldown = 0;
        this.targetCrop = null;
    }

    @Override
    protected void onStop() {
        this.targetCrop = null;
    }

    @Override
    protected void onIdleTick() {
        // Job idle dialogue
        if (--this.jobIdleTalkCooldown <= 0 && !npc.isGagged()) {
            if (npc.getRandom().nextFloat() < 0.01f) {
                speakJobIdleDialogue();
                this.jobIdleTalkCooldown =
                    JOB_IDLE_TALK_MIN +
                    npc
                        .getRandom()
                        .nextInt(JOB_IDLE_TALK_MAX - JOB_IDLE_TALK_MIN);
            }
        }
    }

    @Override
    protected void tickJobSpecific() {
        if (harvestCooldown > 0) harvestCooldown--;

        switch (this.phase) {
            case PHASE_MOVING -> tickMoving();
            case PHASE_HARVESTING -> tickHarvesting();
        }
    }

    // ==================== Farm-Specific Phase Ticks ====================

    private void tickMoving() {
        if (this.targetCrop == null) {
            this.phase = PHASE_SCANNING;
            return;
        }

        // Check if crop still valid
        BlockState state = npc.level().getBlockState(targetCrop);
        if (!isMatureCrop(state)) {
            this.targetCrop = null;
            this.phase = PHASE_SCANNING;
            this.scanTimer = 0;
            return;
        }

        // Move towards crop
        if (--this.pathRecalcTimer <= 0) {
            this.pathRecalcTimer = 10;
            npc
                .getNavigation()
                .moveTo(
                    targetCrop.getX() + 0.5,
                    targetCrop.getY(),
                    targetCrop.getZ() + 0.5,
                    speedModifier
                );
        }

        // Check if close enough to harvest
        double dist = npc.blockPosition().distSqr(targetCrop);
        if (dist <= INTERACT_DISTANCE * INTERACT_DISTANCE) {
            this.phase = PHASE_HARVESTING;
        }
    }

    private void tickHarvesting() {
        if (this.targetCrop == null) {
            this.phase = PHASE_SCANNING;
            return;
        }
        if (harvestCooldown > 0) {
            return; // stay in HARVESTING phase, cooldown decrements in tickJobSpecific()
        }

        Level level = npc.level();
        BlockState state = level.getBlockState(targetCrop);

        if (isMatureCrop(state)) {
            // Get drops
            List<ItemStack> drops = Block.getDrops(
                state,
                (net.minecraft.server.level.ServerLevel) level,
                targetCrop,
                null
            );

            // Add drops to held items (separate seeds for replanting)
            ItemStack seedForReplant = ItemStack.EMPTY;
            for (ItemStack drop : drops) {
                if (isSeed(drop) && seedForReplant.isEmpty()) {
                    seedForReplant = drop.split(1);
                    if (!drop.isEmpty()) {
                        heldItems.add(drop);
                    }
                } else {
                    heldItems.add(drop);
                }
            }

            // Apply yield bonus from experience
            float yieldMult = NpcGoalHelper.getJobYieldMultiplier(
                npc,
                NpcCommand.FARM
            );
            if (
                yieldMult > 1.0f &&
                npc.getRandom().nextFloat() < (yieldMult - 1.0f)
            ) {
                if (!drops.isEmpty()) {
                    ItemStack bonusDrop = drops
                        .get(npc.getRandom().nextInt(drops.size()))
                        .copy();
                    bonusDrop.setCount(1);
                    heldItems.add(bonusDrop);
                }
            }

            // Destroy the crop
            level.destroyBlock(targetCrop, false);

            // Replant if we have a seed
            if (!seedForReplant.isEmpty()) {
                BlockState newCrop = getCropStateForSeed(seedForReplant);
                if (newCrop != null) {
                    level.setBlock(targetCrop, newCrop, 3);
                }
            }

            // Sound effect
            level.playSound(
                null,
                targetCrop,
                SoundEvents.CROP_BREAK,
                SoundSource.BLOCKS,
                1.0f,
                1.0f
            );

            // Look at the crop
            npc
                .getLookControl()
                .setLookAt(
                    targetCrop.getX() + 0.5,
                    targetCrop.getY() + 0.5,
                    targetCrop.getZ() + 0.5
                );

            harvestCooldown = 10;

            // Drain rest from work
            PersonalityState personalityState = npc.getPersonalityState();
            if (personalityState != null) {
                personalityState.getNeeds().drainFromWork(WORK_INTENSITY);
            }
        }

        this.targetCrop = null;
        this.phase = PHASE_SCANNING;
        this.scanTimer = 20; // Short delay before next scan
    }

    // ==================== Farm-Specific Utility ====================

    /**
     * Speak job-specific idle dialogue based on current state.
     */
    private void speakJobIdleDialogue() {
        Player player = this.master;
        if (player == null) {
            player = npc.level().getNearestPlayer(npc, 16);
        }
        if (player == null) return;

        String dialogueId =
            com.tiedup.remake.dialogue.DialogueTriggerSystem.selectProactiveDialogue(
                npc
            );

        if (dialogueId == null || dialogueId.startsWith("idle.")) {
            dialogueId = "jobs.idle.farm";
        }

        com.tiedup.remake.dialogue.EntityDialogueManager.talkByDialogueId(
            npc,
            player,
            dialogueId
        );
    }

    @Nullable
    private BlockPos findMatureCropInZone() {
        if (this.chestPos == null) return null;

        Level level = npc.level();
        BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();

        BlockPos nearest = null;
        double nearestDist = Double.MAX_VALUE;

        for (int x = -WORK_RADIUS; x <= WORK_RADIUS; x++) {
            for (int z = -WORK_RADIUS; z <= WORK_RADIUS; z++) {
                for (int y = -2; y <= 2; y++) {
                    mutable.set(
                        chestPos.getX() + x,
                        chestPos.getY() + y,
                        chestPos.getZ() + z
                    );
                    BlockState state = level.getBlockState(mutable);

                    if (isMatureCrop(state)) {
                        double dist = npc.blockPosition().distSqr(mutable);
                        if (dist < nearestDist) {
                            nearest = mutable.immutable();
                            nearestDist = dist;
                        }
                    }
                }
            }
        }

        return nearest;
    }

    private boolean isMatureCrop(BlockState state) {
        Block block = state.getBlock();

        if (block instanceof CropBlock crop) {
            return crop.isMaxAge(state);
        }
        if (block instanceof StemBlock) {
            return false;
        }
        if (block == Blocks.PUMPKIN || block == Blocks.MELON) {
            return true;
        }
        if (block instanceof SweetBerryBushBlock) {
            return state.getValue(SweetBerryBushBlock.AGE) >= 2;
        }

        return false;
    }

    private boolean isSeed(ItemStack stack) {
        return (
            stack.is(Items.WHEAT_SEEDS) ||
            stack.is(Items.BEETROOT_SEEDS) ||
            stack.is(Items.CARROT) ||
            stack.is(Items.POTATO) ||
            stack.is(Items.MELON_SEEDS) ||
            stack.is(Items.PUMPKIN_SEEDS)
        );
    }

    @Nullable
    private BlockState getCropStateForSeed(ItemStack seed) {
        if (seed.is(Items.WHEAT_SEEDS)) return Blocks.WHEAT.defaultBlockState();
        if (
            seed.is(Items.BEETROOT_SEEDS)
        ) return Blocks.BEETROOTS.defaultBlockState();
        if (seed.is(Items.CARROT)) return Blocks.CARROTS.defaultBlockState();
        if (seed.is(Items.POTATO)) return Blocks.POTATOES.defaultBlockState();
        return null;
    }
}
