package com.tiedup.remake.labor;

import java.util.List;
import java.util.Map;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.RandomSource;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.Nullable;

/**
 * Generator for random labor tasks.
 *
 * DESIGN CHANGE (v2.0):
 * All tasks simplified to "Bring X Items" with automatic tool assignment.
 *
 * Value Guidelines:
 * - Standard ransom: 100-200 emeralds
 * - Target: ~6 tasks average to pay off
 * - Per task value: 18-35 emeralds depending on difficulty
 */
public class LaborTaskGenerator {

    private static final RandomSource RANDOM = RandomSource.create();

    // ==================== TOOL MAPPING ====================

    /**
     * Maps items to the tools needed to collect them.
     * If an item is not in this map, no tool is given.
     */
    private static final Map<Item, ItemStack> TOOL_MAP = Map.ofEntries(
        // Logs → Axe
        Map.entry(Items.OAK_LOG, new ItemStack(Items.IRON_AXE)),
        Map.entry(Items.BIRCH_LOG, new ItemStack(Items.IRON_AXE)),
        Map.entry(Items.SPRUCE_LOG, new ItemStack(Items.IRON_AXE)),
        Map.entry(Items.DARK_OAK_LOG, new ItemStack(Items.IRON_AXE)),
        Map.entry(Items.JUNGLE_LOG, new ItemStack(Items.IRON_AXE)),
        Map.entry(Items.ACACIA_LOG, new ItemStack(Items.IRON_AXE)),
        Map.entry(Items.MANGROVE_LOG, new ItemStack(Items.IRON_AXE)),
        Map.entry(Items.CHERRY_LOG, new ItemStack(Items.IRON_AXE)),
        // Gathering → Shovel
        Map.entry(Items.SAND, new ItemStack(Items.IRON_SHOVEL)),
        Map.entry(Items.GRAVEL, new ItemStack(Items.IRON_SHOVEL)),
        Map.entry(Items.DIRT, new ItemStack(Items.IRON_SHOVEL)),
        Map.entry(Items.CLAY_BALL, new ItemStack(Items.IRON_SHOVEL)),
        // Basic mining → Pickaxe
        Map.entry(Items.COBBLESTONE, new ItemStack(Items.STONE_PICKAXE)),
        // Ores → Pickaxe
        Map.entry(Items.IRON_ORE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.DEEPSLATE_IRON_ORE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.RAW_IRON, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.COAL_ORE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.DEEPSLATE_COAL_ORE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.COAL, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.DIAMOND_ORE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(
            Items.DEEPSLATE_DIAMOND_ORE,
            new ItemStack(Items.IRON_PICKAXE)
        ),
        Map.entry(Items.DIAMOND, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.GOLD_ORE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.DEEPSLATE_GOLD_ORE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.RAW_GOLD, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.COPPER_ORE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(
            Items.DEEPSLATE_COPPER_ORE,
            new ItemStack(Items.IRON_PICKAXE)
        ),
        Map.entry(Items.RAW_COPPER, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.LAPIS_ORE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.DEEPSLATE_LAPIS_ORE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.LAPIS_LAZULI, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.REDSTONE_ORE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(
            Items.DEEPSLATE_REDSTONE_ORE,
            new ItemStack(Items.IRON_PICKAXE)
        ),
        Map.entry(Items.REDSTONE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(Items.EMERALD_ORE, new ItemStack(Items.IRON_PICKAXE)),
        Map.entry(
            Items.DEEPSLATE_EMERALD_ORE,
            new ItemStack(Items.IRON_PICKAXE)
        ),
        Map.entry(Items.EMERALD, new ItemStack(Items.IRON_PICKAXE)),
        // Combat drops → Sword
        Map.entry(Items.ROTTEN_FLESH, new ItemStack(Items.IRON_SWORD)),
        Map.entry(Items.BONE, new ItemStack(Items.IRON_SWORD)),
        Map.entry(Items.STRING, new ItemStack(Items.IRON_SWORD)),
        Map.entry(Items.GUNPOWDER, new ItemStack(Items.IRON_SWORD)),
        Map.entry(Items.SPIDER_EYE, new ItemStack(Items.IRON_SWORD)),
        Map.entry(Items.ARROW, new ItemStack(Items.IRON_SWORD))

        // Items not in this map (e.g., SWEET_BERRIES, KELP, STICK, TORCH, planks) get no tool
    );

    // ==================== TASK POOL ====================

    /**
     * Pool of all available labor tasks.
     * Each entry specifies: item to bring, quota, emerald value.
     */
    private static final List<TaskSpec> TASK_POOL = List.of(
        // Logs (axe provided) — generic "Logs", accepts any type
        new TaskSpec(Items.OAK_LOG, 32, 18),
        new TaskSpec(Items.OAK_LOG, 48, 25),
        new TaskSpec(Items.OAK_LOG, 64, 32),
        // Gathering (shovel provided)
        new TaskSpec(Items.SAND, 32, 10),
        new TaskSpec(Items.GRAVEL, 32, 10),
        new TaskSpec(Items.DIRT, 64, 8),
        new TaskSpec(Items.CLAY_BALL, 16, 14),
        // Basic mining (stone pickaxe provided)
        new TaskSpec(Items.COBBLESTONE, 64, 10),
        new TaskSpec(Items.COBBLESTONE, 32, 8),
        // Easy picks (no tool needed)
        new TaskSpec(Items.SWEET_BERRIES, 16, 12),
        new TaskSpec(Items.KELP, 32, 10),
        // Crafted (no tool needed)
        new TaskSpec(Items.OAK_PLANKS, 64, 12),
        new TaskSpec(Items.STICK, 64, 10),
        new TaskSpec(Items.TORCH, 32, 15),
        // Mining - Coal (common, pickaxe provided)
        new TaskSpec(Items.COAL, 24, 18),
        new TaskSpec(Items.COAL, 32, 22),
        // Mining - Iron (pickaxe provided)
        new TaskSpec(Items.RAW_IRON, 16, 25),
        new TaskSpec(Items.RAW_IRON, 24, 32),
        // Mining - Copper (pickaxe provided)
        new TaskSpec(Items.RAW_COPPER, 20, 20),
        // Mining - Gold (pickaxe provided)
        new TaskSpec(Items.RAW_GOLD, 8, 30),
        // Mining - Lapis (pickaxe provided)
        new TaskSpec(Items.LAPIS_LAZULI, 10, 28),
        // Mining - Redstone (pickaxe provided)
        new TaskSpec(Items.REDSTONE, 12, 22),
        // Mining - Diamond (pickaxe provided, rare, high value)
        new TaskSpec(Items.DIAMOND, 5, 35),
        // Mining - Emerald (pickaxe provided, very rare)
        new TaskSpec(Items.EMERALD, 3, 35),
        // Combat drops (sword provided)
        new TaskSpec(Items.ROTTEN_FLESH, 24, 18),
        new TaskSpec(Items.BONE, 16, 20),
        new TaskSpec(Items.STRING, 32, 20),
        new TaskSpec(Items.GUNPOWDER, 12, 25),
        new TaskSpec(Items.SPIDER_EYE, 8, 20),
        new TaskSpec(Items.ARROW, 16, 18)
    );

    // ==================== GENERATION ====================

    /** Combat task items (require mob kills, only assigned at night). */
    private static final List<Item> COMBAT_ITEMS = List.of(
        Items.ROTTEN_FLESH,
        Items.BONE,
        Items.STRING,
        Items.GUNPOWDER,
        Items.SPIDER_EYE,
        Items.ARROW
    );

    /**
     * Generate a random labor task, filtering combat tasks to nighttime only.
     *
     * @param level The server level (used to check time of day), or null to skip filtering
     */
    public static LaborTask generateRandom(@Nullable ServerLevel level) {
        List<TaskSpec> pool;
        if (level != null && isDay(level)) {
            // Daytime: exclude combat tasks (mobs don't spawn)
            pool = TASK_POOL.stream()
                .filter(spec -> !COMBAT_ITEMS.contains(spec.item()))
                .toList();
        } else {
            pool = TASK_POOL;
        }
        TaskSpec spec = pickRandom(pool);
        ItemStack tool = TOOL_MAP.get(spec.item());
        return new LaborTask(spec.item(), spec.quota(), spec.value(), tool);
    }

    /**
     * Check if it's daytime in the level.
     * Minecraft day cycle: 0-12541 = day, 12542-23999 = night/dusk/dawn.
     * We use 13000-23000 as "night enough for mob spawns".
     */
    private static boolean isDay(ServerLevel level) {
        long timeOfDay = level.getDayTime() % 24000;
        return timeOfDay < 13000;
    }

    /**
     * Generate a task requiring a specific item type.
     * Used for testing or custom scenarios.
     */
    public static LaborTask generateFor(Item item, int quota, int value) {
        ItemStack tool = TOOL_MAP.get(item);
        return new LaborTask(item, quota, value, tool);
    }

    // ==================== UTILITY ====================

    private static <T> T pickRandom(List<T> list) {
        return list.get(RANDOM.nextInt(list.size()));
    }

    /**
     * Task specification record.
     */
    private record TaskSpec(Item item, int quota, int value) {}

    // ==================== RANSOM CALCULATION ====================

    /**
     * Calculate ransom amount based on player equipment/level.
     *
     * @param hasIronArmor Player has iron armor equipped
     * @param hasDiamondArmor Player has diamond/netherite armor equipped
     * @param hasValuables Player has emeralds/diamonds in inventory
     * @return Ransom amount in emeralds
     */
    public static int calculateRansomAmount(
        boolean hasIronArmor,
        boolean hasDiamondArmor,
        boolean hasValuables
    ) {
        int base = 100;

        if (hasDiamondArmor) {
            base = 200;
        } else if (hasIronArmor) {
            base = 150;
        }

        if (hasValuables) {
            base += 25;
        }

        // Add some randomness
        int variance = RANDOM.nextInt(21) - 10; // -10 to +10
        return base + variance;
    }

    /**
     * Estimate number of tasks to pay off a ransom.
     *
     * @param ransomAmount The ransom amount
     * @return Estimated number of tasks
     */
    public static int estimateTasksToPayoff(int ransomAmount) {
        // Average task value is about 25 emeralds
        return (int) Math.ceil(ransomAmount / 25.0);
    }
}
