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.util.MessageDispatcher;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.Style;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.enchantment.EnchantmentHelper;

/**
 * AI Goal for EntityMaster to assign tasks to their pet player.
 *
 * Tasks include:
 * - HEEL: Stay close to master (< 3 blocks)
 * - WAIT_HERE: Stay at current location (< 1 block movement)
 * - FETCH_ITEM: Bring a specific item
 *
 * After assignment, transitions to TASK_WATCH where MasterTaskWatchGoal monitors compliance.
 */
public class MasterTaskAssignGoal extends Goal {

    private final EntityMaster master;

    /** Chance to assign task when following (per tick) */
    private static final float TASK_CHANCE = 0.003f; // ~6% per 10 seconds

    /** Minimum time between tasks (ticks) - 1 minute */
    private static final int TASK_COOLDOWN = 1200;

    /** Task assignment duration (ticks) */
    private static final int ASSIGN_DURATION = 40;

    /** Items that can be requested for FETCH_ITEM task */
    private static final List<Item> FETCHABLE_ITEMS = List.of(
        Items.APPLE,
        Items.BREAD,
        Items.COOKED_BEEF,
        Items.COOKED_CHICKEN,
        Items.GOLDEN_APPLE,
        Items.COOKIE,
        Items.DIAMOND,
        Items.EMERALD,
        Items.IRON_INGOT,
        Items.GOLD_INGOT,
        Items.BONE,
        Items.FLOWER_BANNER_PATTERN,
        Items.ROSE_BUSH,
        Items.DANDELION,
        Items.POPPY
    );

    /** Tasks that can be randomly assigned (excludes events like RANDOM_BIND, DOGWALK) */
    private static final PetTask[] ASSIGNABLE_TASKS = {
        PetTask.HEEL,
        PetTask.WAIT_HERE,
        PetTask.FETCH_ITEM,
        PetTask.KNEEL,
        PetTask.COME,
        PetTask.PRESENT,
        PetTask.SPEAK,
        PetTask.DROP,
        PetTask.FOLLOW_CLOSE,
        PetTask.DEMAND,
    };

    /** Items the Master considers valuable enough to demand (high-value items) */
    private static final Set<Item> HIGH_VALUE_ITEMS = Set.of(
        Items.DIAMOND,
        Items.EMERALD,
        Items.GOLD_INGOT,
        Items.GOLDEN_APPLE,
        Items.ENCHANTED_GOLDEN_APPLE,
        Items.NETHERITE_INGOT,
        Items.NETHER_STAR,
        Items.TOTEM_OF_UNDYING,
        Items.DIAMOND_SWORD,
        Items.DIAMOND_PICKAXE,
        Items.DIAMOND_AXE,
        Items.DIAMOND_CHESTPLATE,
        Items.DIAMOND_HELMET,
        Items.DIAMOND_LEGGINGS,
        Items.DIAMOND_BOOTS,
        Items.NETHERITE_SWORD,
        Items.NETHERITE_PICKAXE,
        Items.NETHERITE_AXE,
        Items.NETHERITE_CHESTPLATE,
        Items.NETHERITE_HELMET,
        Items.NETHERITE_LEGGINGS,
        Items.NETHERITE_BOOTS,
        Items.TRIDENT,
        Items.ELYTRA,
        Items.ENDER_PEARL,
        Items.BLAZE_ROD,
        Items.GHAST_TEAR
    );

    /** Items of moderate value - fallback if no high-value items found */
    private static final Set<Item> MEDIUM_VALUE_ITEMS = Set.of(
        Items.IRON_INGOT,
        Items.GOLD_INGOT,
        Items.LAPIS_LAZULI,
        Items.REDSTONE,
        Items.IRON_SWORD,
        Items.IRON_PICKAXE,
        Items.IRON_AXE,
        Items.IRON_CHESTPLATE,
        Items.COOKED_BEEF,
        Items.COOKED_PORKCHOP,
        Items.GOLDEN_CARROT,
        Items.EXPERIENCE_BOTTLE,
        Items.BOOK,
        Items.NAME_TAG,
        Items.SADDLE,
        Items.COMPASS,
        Items.CLOCK,
        Items.SPYGLASS
    );

    private int assignTimer = 0;
    private long lastTaskTime = 0;
    private boolean hasAssigned = false;
    private PetTask selectedTask = null;

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

    @Override
    public boolean canUse() {
        if (!master.hasPet()) return false;

        MasterState state = master.getStateManager().getCurrentState();

        // Already assigning
        if (state == MasterState.TASK_ASSIGN) return true;

        // Don't assign if already has active task
        if (master.hasActiveTask()) return false;

        // Can only assign from following/observing
        if (state != MasterState.FOLLOWING && state != MasterState.OBSERVING) {
            return false;
        }

        // Check cooldown
        long currentTime = master.level().getGameTime();
        if (currentTime - lastTaskTime < TASK_COOLDOWN) {
            return false;
        }

        // Random chance (modulated by engagement cadence)
        float multiplier = master.getEngagementMultiplier();
        return (
            multiplier > 0 &&
            master.getRandom().nextFloat() < TASK_CHANCE * multiplier
        );
    }

    @Override
    public boolean canContinueToUse() {
        return (
            master.hasPet() &&
            master.getStateManager().getCurrentState() ==
            MasterState.TASK_ASSIGN &&
            assignTimer < ASSIGN_DURATION
        );
    }

    @Override
    public void start() {
        this.assignTimer = 0;
        this.hasAssigned = false;
        this.selectedTask = selectRandomTask();
        master.setMasterState(MasterState.TASK_ASSIGN);
        master.markEngagement();

        TiedUpMod.LOGGER.debug(
            "[MasterTaskAssignGoal] {} assigning task: {}",
            master.getNpcName(),
            selectedTask
        );
    }

    @Override
    public void stop() {
        lastTaskTime = master.level().getGameTime();
        this.assignTimer = 0;
        this.hasAssigned = false;

        // Transition to task watch if task was assigned
        if (master.hasPet() && master.hasActiveTask()) {
            master.setMasterState(MasterState.TASK_WATCH);
        } else if (master.hasPet()) {
            master.setMasterState(MasterState.FOLLOWING);
        }

        this.selectedTask = null;

        TiedUpMod.LOGGER.debug(
            "[MasterTaskAssignGoal] {} task assignment complete",
            master.getNpcName()
        );
    }

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

        // Look at pet
        master.getLookControl().setLookAt(pet, 30.0F, 30.0F);

        // Assign task at start
        if (!hasAssigned && selectedTask != null) {
            assignTask(pet, selectedTask);
            hasAssigned = true;
        }

        assignTimer++;
    }

    /**
     * Select a random task to assign.
     */
    private PetTask selectRandomTask() {
        return ASSIGNABLE_TASKS[master
            .getRandom()
            .nextInt(ASSIGNABLE_TASKS.length)];
    }

    /**
     * Assign a task to the pet.
     */
    private void assignTask(ServerPlayer pet, PetTask task) {
        String message;
        Item requestedItem = null;

        // Handle task-specific setup
        switch (task) {
            case HEEL, FOLLOW_CLOSE -> {
                message = task.getMessageTemplate();
                // Distance tracked to master, no position needed
            }
            case WAIT_HERE -> {
                message = task.getMessageTemplate();
                // Store pet's current position as the anchor point
                master.setTaskStartPosition(pet.position());
            }
            case KNEEL -> {
                message = task.getMessageTemplate();
                // Store pet's current position - must not move
                master.setTaskStartPosition(pet.position());
            }
            case PRESENT -> {
                message = task.getMessageTemplate();
                // Distance tracked to master
            }
            case COME -> {
                message = task.getMessageTemplate();
                // Pet must reach master quickly - no special setup
            }
            case SPEAK -> {
                message = task.getMessageTemplate();
                // Pet must right-click on master - no special setup
            }
            case DROP -> {
                message = task.getMessageTemplate();
                // Pet must empty hands - no special setup
            }
            case FETCH_ITEM -> {
                // Select random item to fetch
                requestedItem = FETCHABLE_ITEMS.get(
                    master.getRandom().nextInt(FETCHABLE_ITEMS.size())
                );
                String itemName = requestedItem.getDescription().getString();
                message = String.format(task.getMessageTemplate(), itemName);
                master.setRequestedItem(requestedItem);
            }
            case DEMAND -> {
                // Scan pet's inventory for the most valuable item
                requestedItem = findMostValuableItem(pet);
                if (requestedItem == null) {
                    // Pet has nothing worth taking - fallback to FETCH_ITEM
                    TiedUpMod.LOGGER.debug(
                        "[MasterTaskAssignGoal] {} found nothing to demand, falling back to FETCH",
                        master.getNpcName()
                    );
                    task = PetTask.FETCH_ITEM;
                    requestedItem = FETCHABLE_ITEMS.get(
                        master.getRandom().nextInt(FETCHABLE_ITEMS.size())
                    );
                    String fallbackName = requestedItem
                        .getDescription()
                        .getString();
                    message = String.format(
                        PetTask.FETCH_ITEM.getMessageTemplate(),
                        fallbackName
                    );
                    master.setRequestedItem(requestedItem);
                    master.setActiveTask(task);
                } else {
                    String itemName = requestedItem
                        .getDescription()
                        .getString();
                    message = String.format(
                        task.getMessageTemplate(),
                        itemName
                    );
                    master.setRequestedItem(requestedItem);
                }
            }
            default -> {
                message = task.getMessageTemplate();
            }
        }

        // Set the active task on the master
        master.setActiveTask(task);

        // FIX: Use MessageDispatcher for consistency with earplug system
        MessageDispatcher.sendChat(
            pet,
            Component.translatable(
                "goal.tiedup.master_assign.task_speech", master.getNpcName(), message
            ).withStyle(Style.EMPTY.withColor(EntityMaster.MASTER_NAME_COLOR))
        );

        // Also use dialogue system for more variation
        String dialogueId = switch (task) {
            case HEEL, FOLLOW_CLOSE -> "petplay.task_heel";
            case WAIT_HERE -> "petplay.task_wait";
            case FETCH_ITEM -> "petplay.task_fetch";
            case KNEEL -> "petplay.task_kneel";
            case COME -> "petplay.task_come";
            case PRESENT -> "petplay.task_present";
            case SPEAK -> "petplay.task_speak";
            case DROP -> "petplay.task_drop";
            case DEMAND -> "petplay.task_demand";
            default -> null;
        };

        if (dialogueId != null) {
            DialogueBridge.talkTo(master, pet, dialogueId);
        }

        TiedUpMod.LOGGER.debug(
            "[MasterTaskAssignGoal] {} assigned {} task to {}{}",
            master.getNpcName(),
            task,
            pet.getName().getString(),
            requestedItem != null
                ? " (item: " + requestedItem.getDescription().getString() + ")"
                : ""
        );
    }

    /**
     * Force assign a specific task (used by external triggers like random events).
     */
    public void forceAssignTask(PetTask task) {
        this.selectedTask = task;
        this.hasAssigned = false;
        master.setMasterState(MasterState.TASK_ASSIGN);
    }

    // DEMAND TASK - INVENTORY SCANNING

    /**
     * Scan pet's inventory and find the most valuable item to demand.
     * Prioritizes: enchanted items > high-value items > medium-value items.
     *
     * @param pet The pet player to scan
     * @return The most valuable item found, or null if inventory is empty/worthless
     */
    @javax.annotation.Nullable
    private Item findMostValuableItem(ServerPlayer pet) {
        List<ItemStack> highValue = new ArrayList<>();
        List<ItemStack> mediumValue = new ArrayList<>();
        List<ItemStack> enchantedItems = new ArrayList<>();

        for (int i = 0; i < pet.getInventory().getContainerSize(); i++) {
            ItemStack stack = pet.getInventory().getItem(i);
            if (stack.isEmpty()) continue;

            Item item = stack.getItem();

            // Enchanted items are always high priority (even enchanted books)
            if (
                stack.isEnchanted() ||
                EnchantmentHelper.getEnchantments(stack).size() > 0
            ) {
                enchantedItems.add(stack);
                continue;
            }

            if (HIGH_VALUE_ITEMS.contains(item)) {
                highValue.add(stack);
            } else if (MEDIUM_VALUE_ITEMS.contains(item)) {
                mediumValue.add(stack);
            }
        }

        // Pick from the highest tier available
        if (!enchantedItems.isEmpty()) {
            return enchantedItems
                .get(master.getRandom().nextInt(enchantedItems.size()))
                .getItem();
        }
        if (!highValue.isEmpty()) {
            return highValue
                .get(master.getRandom().nextInt(highValue.size()))
                .getItem();
        }
        if (!mediumValue.isEmpty()) {
            return mediumValue
                .get(master.getRandom().nextInt(mediumValue.size()))
                .getItem();
        }

        return null; // Nothing worth demanding
    }
}
