package com.tiedup.remake.events.combat;

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.EntityKidnapper;
import com.tiedup.remake.entities.EntityMaid;
import com.tiedup.remake.entities.EntitySlaveTrader;
import com.tiedup.remake.prison.LaborRecord;
import com.tiedup.remake.v2.bondage.BindModeHelper;
import com.tiedup.remake.prison.PrisonerManager;
import com.tiedup.remake.prison.PrisonerRecord;
import com.tiedup.remake.prison.PrisonerState;
import com.tiedup.remake.state.IRestrainable;
import com.tiedup.remake.util.KidnappedHelper;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.event.entity.player.AttackEntityEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

/**
 * Punishes prisoners who attack or attempt to restrain kidnappers, traders, or maids while working.
 *
 * Triggers:
 * - Attacking a protected entity (kidnappers, traders, maids)
 * - Using rope/restraint items on a protected entity
 *
 * Punishments (applied immediately):
 * - Shock (damage + message)
 * - Debt increase (+25 emeralds)
 * - Task marked as failed (no payment)
 * - Equipment reclaimed
 * - Immediate teleportation back to cell
 * - State changed to IMPRISONED (resting)
 * - Attack/interaction cancelled (no damage to target)
 *
 * This prevents prisoners from attacking or restraining their captors during labor tasks.
 */
@Mod.EventBusSubscriber(modid = TiedUpMod.MOD_ID)
public class LaborAttackPunishmentHandler {

    /** Debt increase per attack */
    private static final int DEBT_INCREASE_PER_ATTACK = 25;

    /** Base shock damage */
    private static final float BASE_SHOCK_DAMAGE = 3.0f;

    /**
     * Detect when a prisoner attacks a kidnapper/trader/maid during labor.
     */
    @SubscribeEvent
    public static void onPlayerAttackEntity(AttackEntityEvent event) {
        Player player = event.getEntity();
        Entity target = event.getTarget();

        // Server-side only
        if (player.level().isClientSide) {
            return;
        }

        // Only handle ServerPlayer
        if (!(player instanceof ServerPlayer serverPlayer)) {
            return;
        }

        // Only handle ServerLevel
        if (!(player.level() instanceof ServerLevel serverLevel)) {
            return;
        }

        // Check if target is a kidnapper, trader, or maid
        boolean isProtectedEntity =
            target instanceof EntityKidnapper ||
            target instanceof EntitySlaveTrader ||
            target instanceof EntityMaid;

        if (!isProtectedEntity) {
            return;
        }

        // Check if player is a prisoner in WORKING state
        PrisonerManager manager = PrisonerManager.get(serverLevel);
        PrisonerRecord record = manager.getRecord(serverPlayer.getUUID());

        if (record.getState() != PrisonerState.WORKING) {
            return; // Not working, no punishment
        }

        // PUNISH THE PRISONER
        punishPrisonerForAttack(serverPlayer, serverLevel, record, target);

        // Cancel the attack
        event.setCanceled(true);
    }

    /**
     * Detect when a prisoner tries to use rope/restraint items on kidnapper/trader/maid during labor.
     */
    @SubscribeEvent
    public static void onPlayerInteractEntity(
        PlayerInteractEvent.EntityInteract event
    ) {
        Player player = event.getEntity();
        Entity target = event.getTarget();
        InteractionHand hand = event.getHand();

        // Server-side only
        if (player.level().isClientSide) {
            return;
        }

        // Only handle ServerPlayer
        if (!(player instanceof ServerPlayer serverPlayer)) {
            return;
        }

        // Only handle ServerLevel
        if (!(player.level() instanceof ServerLevel serverLevel)) {
            return;
        }

        // Check if target is a kidnapper, trader, or maid
        boolean isProtectedEntity =
            target instanceof EntityKidnapper ||
            target instanceof EntitySlaveTrader ||
            target instanceof EntityMaid;

        if (!isProtectedEntity) {
            return;
        }

        // Check if player is a prisoner in WORKING state
        PrisonerManager manager = PrisonerManager.get(serverLevel);
        PrisonerRecord record = manager.getRecord(serverPlayer.getUUID());

        if (record.getState() != PrisonerState.WORKING) {
            return; // Not working, no punishment
        }

        // Check if player is holding a restraint item (rope, chain, etc.)
        ItemStack heldItem = serverPlayer.getItemInHand(hand);
        if (!BindModeHelper.isBindItem(heldItem)) {
            return; // Not a restraint item
        }

        // PUNISH THE PRISONER
        punishPrisonerForAttack(serverPlayer, serverLevel, record, target);

        // Cancel the interaction
        event.setCanceled(true);

        TiedUpMod.LOGGER.info(
            "[LaborAttackPunishmentHandler] Prisoner {} attempted to restrain {} during labor - punished",
            serverPlayer.getName().getString(),
            target instanceof EntityKidnapper kidnapper
                ? kidnapper.getNpcName()
                : target instanceof EntitySlaveTrader trader
                    ? trader.getNpcName()
                    : target instanceof EntityMaid maid
                        ? maid.getNpcName()
                        : "captor"
        );
    }

    /**
     * Apply punishment to prisoner for attacking protected entity.
     */
    private static void punishPrisonerForAttack(
        ServerPlayer prisoner,
        ServerLevel level,
        PrisonerRecord record,
        Entity target
    ) {
        IRestrainable kidnappedState = KidnappedHelper.getKidnappedState(
            prisoner
        );
        if (kidnappedState == null) {
            return;
        }

        // 1. Shock the prisoner
        String targetName = "your captor";
        if (target instanceof EntityKidnapper kidnapper) {
            targetName = kidnapper.getNpcName();
        } else if (target instanceof EntitySlaveTrader trader) {
            targetName = trader.getNpcName();
        } else if (target instanceof EntityMaid maid) {
            targetName = maid.getNpcName();
        }

        String shockMessage = String.format(
            "You DARE attack %s? You'll pay for this insolence!",
            targetName
        );

        kidnappedState.shockKidnapped(shockMessage, BASE_SHOCK_DAMAGE);

        // 2. Increase debt
        PrisonerManager manager = PrisonerManager.get(level);
        com.tiedup.remake.prison.RansomRecord ransomRecord =
            manager.getRansomRecord(prisoner.getUUID());
        if (ransomRecord != null) {
            manager.increaseDebt(prisoner.getUUID(), DEBT_INCREASE_PER_ATTACK);

            prisoner.sendSystemMessage(
                Component.translatable(
                    "msg.tiedup.event.debt_increased",
                    DEBT_INCREASE_PER_ATTACK,
                    targetName
                ).withStyle(ChatFormatting.RED, ChatFormatting.BOLD)
            );
        }

        // 3. CRITICAL FIX: Collect task items, reclaim equipment, and confiscate everything
        LaborRecord laborRecord = manager.getLaborRecord(prisoner.getUUID());
        com.tiedup.remake.labor.LaborTask task = laborRecord.getTask();

        // Find cell via PrisonerRecord.getCellId() — CellRegistryV2 won't have the prisoner
        // during WORKING state because extractFromCell() removes them from the registry.
        com.tiedup.remake.cells.CellRegistryV2 cellRegistry =
            com.tiedup.remake.cells.CellRegistryV2.get(level);
        java.util.UUID cellId = record.getCellId();
        com.tiedup.remake.cells.CellDataV2 cell =
            cellId != null ? cellRegistry.getCell(cellId) : null;

        if (task != null) {
            // Collect task items (prevent player keeping valuable items like diamonds)
            java.util.List<net.minecraft.world.item.ItemStack> collectedItems =
                task.collectItems(prisoner);
            TiedUpMod.LOGGER.debug(
                "[LaborAttackPunishmentHandler] Collected {} task items from {} before punishment",
                collectedItems.size(),
                prisoner.getName().getString()
            );

            // Reclaim labor tools
            java.util.List<net.minecraft.world.item.ItemStack> reclaimedTools =
                task.reclaimEquipment(prisoner);
            TiedUpMod.LOGGER.debug(
                "[LaborAttackPunishmentHandler] Reclaimed {} tools from {} before punishment",
                reclaimedTools.size(),
                prisoner.getName().getString()
            );

            if (cell != null) {
                java.util.List<net.minecraft.world.item.ItemStack> allItems =
                    new java.util.ArrayList<>();
                allItems.addAll(collectedItems);
                allItems.addAll(reclaimedTools);

                if (!allItems.isEmpty()) {
                    depositPunishmentItems(level, cell, allItems);
                }
            }
        }

        // Confiscate remaining contraband (anything picked up during labor)
        if (cell != null && !prisoner.getInventory().isEmpty()) {
            com.tiedup.remake.cells.ConfiscatedInventoryRegistry registry =
                com.tiedup.remake.cells.ConfiscatedInventoryRegistry.get(level);

            java.util.List<net.minecraft.core.BlockPos> campChests =
                findCampLootChests(level, cell);
            if (!campChests.isEmpty()) {
                registry.dumpInventoryToChest(prisoner, campChests.get(0));
                TiedUpMod.LOGGER.debug(
                    "[LaborAttackPunishmentHandler] Confiscated remaining contraband from {}",
                    prisoner.getName().getString()
                );
            }
        }

        laborRecord.setTaskFailed(true);

        // 4. Warning message
        prisoner.sendSystemMessage(
            Component.translatable(
                "msg.tiedup.event.task_failed"
            ).withStyle(ChatFormatting.DARK_RED)
        );

        // 5. Return prisoner to cell immediately (punishment)

        if (cell != null) {
            // Teleport to cell
            net.minecraft.core.BlockPos spawnPoint = cell
                .getSpawnPoint()
                .above();
            com.tiedup.remake.util.teleport.Position teleportTarget =
                new com.tiedup.remake.util.teleport.Position(
                    spawnPoint,
                    level.dimension()
                );
            com.tiedup.remake.util.teleport.TeleportHelper.teleportEntity(
                prisoner,
                teleportTarget
            );

            // Reassign prisoner to cell registry (was removed during extract)
            cellRegistry.assignPrisoner(cell.getId(), prisoner.getUUID());

            // Transition to IMPRISONED state and start rest
            long currentTime = level.getGameTime();
            record.setState(PrisonerState.IMPRISONED, currentTime);
            laborRecord.setTask(null); // CRITICAL: Clear task to prevent reuse after punishment
            laborRecord.startRest(currentTime);
            laborRecord.setEscortMaidId(null);

            prisoner.sendSystemMessage(
                Component.translatable(
                    "msg.tiedup.event.returned_to_cell"
                ).withStyle(ChatFormatting.RED, ChatFormatting.BOLD)
            );

            TiedUpMod.LOGGER.info(
                "[LaborAttackPunishmentHandler] Prisoner {} attacked {} during labor - punished (shocked, +{} debt, task failed, items confiscated, returned to cell)",
                prisoner.getName().getString(),
                targetName,
                DEBT_INCREASE_PER_ATTACK
            );
        } else {
            TiedUpMod.LOGGER.warn(
                "[LaborAttackPunishmentHandler] Could not return {} to cell - no cell found! (cellId={}, record={})",
                prisoner.getName().getString(),
                cellId != null ? cellId.toString().substring(0, 8) : "null",
                record
            );
        }
    }

    /**
     * Deposit punishment items (task items + tools) in camp chests.
     * Items are confiscated as punishment and stored in camp.
     */
    private static void depositPunishmentItems(
        ServerLevel level,
        com.tiedup.remake.cells.CellDataV2 cell,
        java.util.List<net.minecraft.world.item.ItemStack> items
    ) {
        if (items.isEmpty()) {
            return;
        }

        java.util.UUID campId = cell.getOwnerId();
        if (campId == null) {
            TiedUpMod.LOGGER.warn(
                "[LaborAttackPunishmentHandler] Cell has no camp owner - cannot deposit punishment items"
            );
            return;
        }

        java.util.List<net.minecraft.core.BlockPos> campChests =
            findCampLootChests(level, cell);

        if (campChests.isEmpty()) {
            // Fallback: drop at camp center
            com.tiedup.remake.cells.CampOwnership campOwnership =
                com.tiedup.remake.cells.CampOwnership.get(level);
            com.tiedup.remake.cells.CampOwnership.CampData camp =
                campOwnership.getCamp(campId);
            if (camp != null && camp.getCenter() != null) {
                net.minecraft.core.BlockPos center = camp.getCenter();
                TiedUpMod.LOGGER.warn(
                    "[LaborAttackPunishmentHandler] No LOOT chests found - dropping punishment items at camp center {}",
                    center.toShortString()
                );

                for (net.minecraft.world.item.ItemStack stack : items) {
                    if (stack.isEmpty()) continue;
                    net.minecraft.world.entity.item.ItemEntity itemEntity =
                        new net.minecraft.world.entity.item.ItemEntity(
                            level,
                            center.getX() + 0.5,
                            center.getY() + 1.0,
                            center.getZ() + 0.5,
                            stack
                        );
                    level.addFreshEntity(itemEntity);
                }
            }
            return;
        }

        // Use unified inventory system for smart chest rotation
        com.tiedup.remake.cells.ConfiscatedInventoryRegistry registry =
            com.tiedup.remake.cells.ConfiscatedInventoryRegistry.get(level);

        int deposited = registry.depositItemsInChests(items, campChests, level);

        TiedUpMod.LOGGER.info(
            "[LaborAttackPunishmentHandler] Deposited {} punishment items in {} camp LOOT chests",
            deposited,
            campChests.size()
        );
    }

    /**
     * Find all LOOT chests for a camp.
     * Delegates to ItemService which handles fast-path + lazy discovery.
     */
    private static java.util.List<
        net.minecraft.core.BlockPos
    > findCampLootChests(
        ServerLevel level,
        com.tiedup.remake.cells.CellDataV2 cell
    ) {
        java.util.UUID campId = cell.getOwnerId();
        if (campId == null) return java.util.List.of();

        return com.tiedup.remake.prison.service.ItemService.get().findAllCampChests(
            level,
            campId
        );
    }
}
