package com.tiedup.remake.cells;

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.items.base.ILockable;
import com.tiedup.remake.prison.PrisonerManager;
import com.tiedup.remake.v2.bondage.CollarHelper;
import com.tiedup.remake.state.IRestrainable;
import com.tiedup.remake.util.KidnappedHelper;
import com.tiedup.remake.v2.BodyRegionV2;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import net.minecraft.ChatFormatting;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;

/**
 * Handles camp lifecycle events: camp death, prisoner freeing, and camp defense alerts.
 *
 * <p>This is a stateless utility class. All state lives in {@link CampOwnership}
 * (the SavedData singleton). Methods here orchestrate multi-system side effects
 * that don't belong in the data layer.
 */
public final class CampLifecycleManager {

    private CampLifecycleManager() {} // utility class

    /**
     * Mark a camp as dead (trader killed) and perform full cleanup.
     * This:
     * - Cancels all ransoms for the camp's prisoners
     * - Frees all prisoners (untie, unlock collars)
     * - Clears all labor states
     * - Removes all cells belonging to the camp
     * - Makes the camp inactive
     *
     * @param campId The camp UUID
     * @param level  The server level for entity lookups
     */
    public static void markCampDead(UUID campId, ServerLevel level) {
        CampOwnership ownership = CampOwnership.get(level);
        CampOwnership.CampData data = ownership.getCamp(campId);
        if (data == null) {
            return;
        }

        UUID traderUUID = data.getTraderUUID();

        TiedUpMod.LOGGER.info(
            "[CampLifecycleManager] Camp {} dying - freeing all prisoners",
            campId.toString().substring(0, 8)
        );

        // PERFORMANCE FIX: Use PrisonerManager's index instead of CellRegistry
        // This is O(1) lookup instead of iterating all cells
        PrisonerManager manager = PrisonerManager.get(level);
        Set<UUID> prisonerIds = manager.getPrisonersInCamp(campId);

        TiedUpMod.LOGGER.debug(
            "[CampLifecycleManager] Found {} prisoners in camp {} via index",
            prisonerIds.size(),
            campId.toString().substring(0, 8)
        );

        // Cancel ransoms and free each prisoner
        for (UUID prisonerId : prisonerIds) {
            // Cancel ransom by clearing it
            if (manager.getRansomRecord(prisonerId) != null) {
                manager.setRansomRecord(prisonerId, null);
                TiedUpMod.LOGGER.debug(
                    "[CampLifecycleManager] Cancelled ransom for prisoner {}",
                    prisonerId.toString().substring(0, 8)
                );
            }

            // Free the prisoner
            ServerPlayer prisoner = level
                .getServer()
                .getPlayerList()
                .getPlayer(prisonerId);
            if (prisoner != null) {
                // Online: untie, unlock collar, release with 5-min grace period
                removeLaborTools(prisoner);
                freePrisonerOnCampDeath(prisoner, traderUUID, level);
                // Cell cleanup only -- freePrisonerOnCampDeath already called release()
                // which transitions to PROTECTED with grace period.
                // Calling escape() here would override PROTECTED->FREE, losing the grace.
                CellRegistryV2.get(level).releasePrisonerFromAllCells(
                    prisonerId
                );
            } else {
                // Offline: full escape via PrisonerService (no grace period needed)
                com.tiedup.remake.prison.service.EscapeMonitorService.get().escape(
                    level,
                    prisonerId,
                    "camp death"
                );
            }
            ownership.unmarkPrisonerProcessed(prisonerId);
        }

        // HIGH FIX: Remove all cells belonging to this camp from CellRegistryV2
        // Prevents memory leak and stale data in indices
        CellRegistryV2 cellRegistry = CellRegistryV2.get(level);
        List<CellDataV2> campCells = cellRegistry.getCellsByCamp(campId);
        for (CellDataV2 cell : campCells) {
            cellRegistry.removeCell(cell.getId());
            TiedUpMod.LOGGER.debug(
                "[CampLifecycleManager] Removed cell {} from registry",
                cell.getId().toString().substring(0, 8)
            );
        }
        TiedUpMod.LOGGER.info(
            "[CampLifecycleManager] Removed {} cells for dead camp {}",
            campCells.size(),
            campId.toString().substring(0, 8)
        );

        // Mark camp as dead
        data.setAlive(false);
        ownership.setDirty();

        TiedUpMod.LOGGER.info(
            "[CampLifecycleManager] Camp {} is now dead, {} prisoners freed",
            campId.toString().substring(0, 8),
            prisonerIds.size()
        );
    }

    /**
     * Alert all NPCs in a camp to defend against an attacker.
     * Called when someone tries to restrain the trader or maid.
     *
     * @param campId   The camp UUID
     * @param attacker The player attacking
     * @param level    The server level
     */
    public static void alertCampToDefend(
        UUID campId,
        Player attacker,
        ServerLevel level
    ) {
        CampOwnership ownership = CampOwnership.get(level);
        CampOwnership.CampData camp = ownership.getCamp(campId);
        if (camp == null) return;

        int alertedCount = 0;

        // 1. Alert the trader
        UUID traderUUID = camp.getTraderUUID();
        if (traderUUID != null) {
            net.minecraft.world.entity.Entity traderEntity = level.getEntity(
                traderUUID
            );
            if (
                traderEntity instanceof
                    com.tiedup.remake.entities.EntitySlaveTrader trader
            ) {
                if (trader.isAlive() && !trader.isTiedUp()) {
                    trader.setTarget(attacker);
                    trader.setLastAttacker(attacker);
                    alertedCount++;
                }
            }
        }

        // 2. Alert the maid
        UUID maidUUID = camp.getMaidUUID();
        if (maidUUID != null) {
            net.minecraft.world.entity.Entity maidEntity = level.getEntity(
                maidUUID
            );
            if (
                maidEntity instanceof com.tiedup.remake.entities.EntityMaid maid
            ) {
                if (maid.isAlive() && !maid.isTiedUp()) {
                    maid.setTarget(attacker);
                    maid.setMaidState(
                        com.tiedup.remake.entities.ai.maid.MaidState.DEFENDING
                    );
                    alertedCount++;
                }
            }
        }

        // 3. Alert all kidnappers
        Set<UUID> kidnapperUUIDs = camp.getLinkedKidnappers();
        for (UUID kidnapperUUID : kidnapperUUIDs) {
            net.minecraft.world.entity.Entity entity = level.getEntity(
                kidnapperUUID
            );
            if (
                entity instanceof
                    com.tiedup.remake.entities.EntityKidnapper kidnapper
            ) {
                if (kidnapper.isAlive() && !kidnapper.isTiedUp()) {
                    kidnapper.setTarget(attacker);
                    kidnapper.setLastAttacker(attacker);
                    alertedCount++;
                }
            }
        }

        TiedUpMod.LOGGER.info(
            "[CampLifecycleManager] Camp {} alerted {} NPCs to defend against {}",
            campId.toString().substring(0, 8),
            alertedCount,
            attacker.getName().getString()
        );
    }

    // ==================== PRIVATE HELPERS ====================

    /**
     * Free a prisoner when their camp dies.
     * Untie, unlock collar, cancel sale, notify.
     * Uses legitimate removal flag to prevent alerting kidnappers.
     */
    private static void freePrisonerOnCampDeath(
        ServerPlayer prisoner,
        UUID traderUUID,
        ServerLevel level
    ) {
        IRestrainable state = KidnappedHelper.getKidnappedState(prisoner);
        if (state == null) {
            return;
        }

        // Suppress collar removal alerts - this is a legitimate release (camp death)
        CollarHelper.runWithSuppressedAlert(() -> {
            // Unlock collar if owned by the dead camp/trader
            unlockCollarIfOwnedBy(prisoner, state, traderUUID);

            // Remove all restraints (including collar if any)
            state.untie(true);

            // Cancel sale
            state.cancelSale();
        });

        // Clear client HUD
        com.tiedup.remake.network.ModNetwork.sendToPlayer(
            new com.tiedup.remake.network.labor.PacketSyncLaborProgress(),
            prisoner
        );

        // Notify prisoner
        prisoner.sendSystemMessage(
            Component.translatable("msg.tiedup.camp.captor_died")
                .withStyle(ChatFormatting.GREEN, ChatFormatting.BOLD)
        );

        // Grant grace period (5 minutes = 6000 ticks)
        PrisonerManager manager = PrisonerManager.get(level);
        manager.release(prisoner.getUUID(), level.getGameTime(), 6000);

        prisoner.sendSystemMessage(
            Component.translatable("msg.tiedup.camp.grace_period")
                .withStyle(ChatFormatting.AQUA)
        );

        TiedUpMod.LOGGER.info(
            "[CampLifecycleManager] Freed prisoner {} on camp death (no alert)",
            prisoner.getName().getString()
        );
    }

    /**
     * Unlock a prisoner's collar if it's owned by the specified owner (trader/kidnapper).
     */
    private static void unlockCollarIfOwnedBy(
        ServerPlayer prisoner,
        IRestrainable state,
        UUID ownerUUID
    ) {
        ItemStack collar = state.getEquipment(BodyRegionV2.NECK);
        if (collar.isEmpty()) {
            return;
        }

        if (CollarHelper.isCollar(collar)) {
            List<UUID> owners = CollarHelper.getOwners(collar);

            // If the dead trader/camp is an owner, unlock the collar
            if (owners.contains(ownerUUID)) {
                if (collar.getItem() instanceof ILockable lockable) {
                    lockable.setLockedByKeyUUID(collar, null); // Unlock and clear
                }
                TiedUpMod.LOGGER.debug(
                    "[CampLifecycleManager] Unlocked collar for {} (owner {} died)",
                    prisoner.getName().getString(),
                    ownerUUID.toString().substring(0, 8)
                );
            }
        }
    }

    /**
     * SECURITY: Remove all labor tools from player inventory.
     * Prevents prisoners from keeping unbreakable tools when freed/released.
     */
    private static void removeLaborTools(ServerPlayer player) {
        var inventory = player.getInventory();
        int removedCount = 0;

        for (int i = 0; i < inventory.getContainerSize(); i++) {
            ItemStack stack = inventory.getItem(i);
            if (!stack.isEmpty() && stack.hasTag()) {
                CompoundTag tag = stack.getTag();
                if (tag != null && tag.getBoolean("LaborTool")) {
                    inventory.setItem(i, ItemStack.EMPTY);
                    removedCount++;
                }
            }
        }

        if (removedCount > 0) {
            TiedUpMod.LOGGER.debug(
                "[CampLifecycleManager] Removed {} labor tools from {} on camp death",
                removedCount,
                player.getName().getString()
            );
        }
    }
}
