package com.tiedup.remake.events.captivity;

import com.tiedup.remake.core.SettingsAccessor;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.LeashProxyEntity;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.v2.bondage.CollarHelper;
import com.tiedup.remake.state.IPlayerLeashAccess;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.util.KidnappedHelper;
import com.tiedup.remake.v2.BodyRegionV2;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

/**
 * Event handler for master-slave (enslavement) interactions.
 *
 * <h2>Key Mechanisms</h2>
 * <ul>
 *   <li><b>Enslavement:</b> Right-click with Lead on tied player → enslaves them</li>
 *   <li><b>Freeing:</b> Right-click with empty hand on your slave → frees them</li>
 * </ul>
 *
 * <h2>Leash System</h2>
 * Uses a proxy-based leash system where a {@link LeashProxyEntity} follows the player
 * and holds the leash. The player does NOT mount anything - traction is applied via push().
 *
 * @see PlayerBindState#free()
 * @see LeashProxyEntity
 * @see IPlayerLeashAccess
 */
@Mod.EventBusSubscriber(modid = TiedUpMod.MOD_ID)
public class PlayerEnslavementHandler {

    /**
     * Prevent enslaved players from attacking/breaking their constraints.
     * Handles Left-Click (Attack) events.
     */
    @SubscribeEvent
    public static void onPlayerAttackEntity(
        net.minecraftforge.event.entity.player.AttackEntityEvent event
    ) {
        Player player = event.getEntity();
        Entity target = event.getTarget();

        // Check if player is leashed (enslaved) via proxy system
        if (
            player instanceof IPlayerLeashAccess access &&
            access.tiedup$isLeashed()
        ) {
            // Prevent breaking the LeashKnot or the LeashProxy itself
            if (
                target instanceof
                    net.minecraft.world.entity.decoration.LeashFenceKnotEntity ||
                target instanceof LeashProxyEntity
            ) {
                event.setCanceled(true);
            }
        }
    }

    /**
     * Handle player interactions with other players for enslavement/freeing.
     *
     * Uses IBondageState for condition checks (isEnslavable)
     * Note: Enslavement system (getEnslavedBy, free) remains PlayerBindState-specific
     */
    @SubscribeEvent
    public static void onPlayerInteractEntity(
        PlayerInteractEvent.EntityInteract event
    ) {
        Player master = event.getEntity();
        Entity target = event.getTarget();

        // 1. Prevention Logic: Slaves cannot interact with leash knots or proxies
        if (
            master instanceof IPlayerLeashAccess access &&
            access.tiedup$isLeashed()
        ) {
            if (
                target instanceof
                    net.minecraft.world.entity.decoration.LeashFenceKnotEntity ||
                target instanceof LeashProxyEntity
            ) {
                event.setCanceled(true);
                return;
            }
        }

        // Only handle player-to-player interactions for enslavement logic
        if (!(target instanceof Player)) {
            return;
        }
        Player slave = (Player) target;

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

        // Only handle MAIN_HAND to avoid double processing
        if (event.getHand() != net.minecraft.world.InteractionHand.MAIN_HAND) {
            return;
        }

        // Check if enslavement is enabled
        if (
            !SettingsAccessor.isEnslavementEnabled(
                master.level().getGameRules()
            )
        ) {
            return;
        }

        // Get IBondageState for condition checks
        IBondageState slaveKidnappedState = KidnappedHelper.getKidnappedState(
            slave
        );
        if (slaveKidnappedState == null) {
            return;
        }

        // Get PlayerBindState for enslavement operations (Player-only system)
        PlayerBindState masterState = PlayerBindState.getInstance(master);
        PlayerBindState slaveState = PlayerBindState.getInstance(slave);

        if (masterState == null || slaveState == null) {
            return;
        }

        ItemStack heldItem = master.getItemInHand(event.getHand());

        // Scenario 1: Enslavement with Lead
        if (heldItem.is(Items.LEAD)) {
            // Check if target is enslavable (using IBondageState)
            if (!slaveKidnappedState.isEnslavable()) {
                // Exception: collar owner can capture even if not tied
                boolean canCapture = false;
                if (slaveKidnappedState.hasCollar()) {
                    ItemStack collar = slaveKidnappedState.getEquipment(
                        BodyRegionV2.NECK
                    );
                    if (CollarHelper.isCollar(collar)) {
                        if (
                            CollarHelper
                                .getOwners(collar)
                                .contains(master.getUUID())
                        ) {
                            canCapture = true;
                        }
                    }
                }
                if (!canCapture) {
                    TiedUpMod.LOGGER.debug(
                        "[PlayerEnslavementHandler] {} cannot be enslaved - not tied and not collar owner",
                        slave.getName().getString()
                    );
                    return;
                }
            }

            if (slaveState.isCaptive()) {
                TiedUpMod.LOGGER.debug(
                    "[PlayerEnslavementHandler] {} is already captured",
                    slave.getName().getString()
                );
                return;
            }

            // Attempt capture
            boolean success = slaveState.getCapturedBy(
                masterState.getCaptorManager()
            );

            if (success) {
                heldItem.shrink(1);
                TiedUpMod.LOGGER.info(
                    "[PlayerEnslavementHandler] {} enslaved {} (lead consumed)",
                    master.getName().getString(),
                    slave.getName().getString()
                );
                event.setCanceled(true);
            } else {
                TiedUpMod.LOGGER.warn(
                    "[PlayerEnslavementHandler] Failed to enslave {} by {}",
                    slave.getName().getString(),
                    master.getName().getString()
                );
            }
        }
        // Scenario 2: Freeing with Empty Hand
        else if (heldItem.isEmpty()) {
            if (!slaveState.isCaptive()) return;

            if (slaveState.getCaptor() != masterState.getCaptorManager()) {
                TiedUpMod.LOGGER.debug(
                    "[PlayerEnslavementHandler] {} tried to free {} but is not the captor",
                    master.getName().getString(),
                    slave.getName().getString()
                );
                return;
            }

            slaveState.free();
            TiedUpMod.LOGGER.info(
                "[PlayerEnslavementHandler] {} freed {}",
                master.getName().getString(),
                slave.getName().getString()
            );
            event.setCanceled(true);
        }
    }

    /**
     * Periodic check for enslaved players.
     *
     */
    @SubscribeEvent
    public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
        if (event.phase != TickEvent.Phase.END) return;
        Player player = event.player;
        if (player.level().isClientSide) return;
        if (player.tickCount % 20 != 0) return;

        PlayerBindState state = PlayerBindState.getInstance(player);
        if (state == null) return;

        if (state.isCaptive()) {
            state.checkStillCaptive();
        }
        state.getCaptorManager().cleanupInvalidCaptives();
    }
}
