package com.tiedup.remake.events.captivity;

import com.tiedup.remake.core.SystemMessageManager;
import com.tiedup.remake.core.SystemMessageManager.MessageCategory;
import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.entities.LeashProxyEntity;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.state.PlayerBindState;
import com.tiedup.remake.state.PlayerCaptorManager;
import com.tiedup.remake.util.KidnappedHelper;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.event.entity.EntityMountEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

/**
 * Handles forced seating for captives.
 *
 * Flow:
 * 1. [ALT] + right-click empty vehicle → free captive + mount on vehicle
 * 2. [ALT] + right-click vehicle with tied player → dismount + re-capture
 * 3. Owner enters vehicle with tied player → swap (owner = driver)
 * 4. Tied player Shift → blocked
 * 5. Vehicle destroyed → tied player dismounts, stays free
 *
 * Note: In the vehicle, the captive has NO leash. The "tied up" status
 * (isTiedUp) is preserved, which blocks vehicle control and dismount.
 */
@Mod.EventBusSubscriber(
    modid = TiedUpMod.MOD_ID,
    bus = Mod.EventBusSubscriber.Bus.FORGE
)
public class ForcedSeatingHandler {

    /** Track which players have the Force Seat keybind pressed (server-side) */
    private static final Map<UUID, Boolean> forceSeatPressed =
        new ConcurrentHashMap<>();

    /** Track forced dismounts in progress to avoid blocking our own operations */
    private static final Map<UUID, Boolean> forcedDismountInProgress =
        new ConcurrentHashMap<>();

    /**
     * Update the Force Seat keybind state for a player.
     * Called from PacketForceSeatModifier.
     */
    public static void setForceSeatPressed(UUID playerId, boolean pressed) {
        if (pressed) {
            forceSeatPressed.put(playerId, true);
        } else {
            forceSeatPressed.remove(playerId);
        }
    }

    /**
     * Check if a player has the Force Seat keybind pressed.
     */
    public static boolean isForceSeatPressed(Player player) {
        return forceSeatPressed.getOrDefault(player.getUUID(), false);
    }

    /**
     * Clean up keybind state when player disconnects.
     */
    public static void clearPlayer(UUID playerId) {
        forceSeatPressed.remove(playerId);
        forcedDismountInProgress.remove(playerId);
    }

    // ========== ALT + CLICK ON ENTITY ==========

    /**
     * Handle ALT + right-click on entity.
     * - If vehicle has tied player → dismount + re-capture
     * - If vehicle is empty → free captive + mount
     */
    @SubscribeEvent(priority = EventPriority.HIGHEST)
    public static void onPlayerInteractEntity(
        PlayerInteractEvent.EntityInteract event
    ) {
        if (event.getLevel().isClientSide) return;

        Player owner = event.getEntity();
        Entity target = event.getTarget();

        // Furniture handles its own seating — skip forced seating logic
        if (
            target instanceof com.tiedup.remake.v2.furniture.ISeatProvider
        ) return;

        // Only process if Force Seat keybind is pressed
        if (!isForceSeatPressed(owner)) return;

        // Skip proxies and players
        if (target instanceof LeashProxyEntity) return;
        if (target instanceof Player) return;

        // Get owner's state
        PlayerBindState ownerState = PlayerBindState.getInstance(owner);
        if (ownerState == null) return;

        PlayerCaptorManager captorManager = ownerState.getCaptorManager();

        // === CASE 1: Vehicle with tied player → dismount and re-capture ===
        for (Entity passenger : target.getPassengers()) {
            if (passenger instanceof Player tiedPlayer && tiedPlayer != owner) {
                IBondageState tiedState = KidnappedHelper.getKidnappedState(
                    tiedPlayer
                );

                if (tiedState != null && tiedState.isTiedUp()) {
                    // Cancel the event first
                    event.setCanceled(true);

                    // Mark forced dismount in progress
                    forcedDismountInProgress.put(tiedPlayer.getUUID(), true);

                    // Schedule dismount for next tick
                    target
                        .getServer()
                        .execute(() -> {
                            try {
                                // Dismount the tied player
                                tiedPlayer.stopRiding();

                                // Teleport slightly away from vehicle
                                double offsetX =
                                    (target.level().random.nextDouble() - 0.5) *
                                    2;
                                double offsetZ =
                                    (target.level().random.nextDouble() - 0.5) *
                                    2;
                                tiedPlayer.teleportTo(
                                    target.getX() + offsetX,
                                    target.getY() + 0.5,
                                    target.getZ() + offsetZ
                                );

                                // Re-capture (creates proxy + leash)
                                if (captorManager != null) {
                                    tiedState.getCapturedBy(captorManager);
                                }

                                TiedUpMod.LOGGER.debug(
                                    "[ForcedSeating] {} dismounted {} from vehicle",
                                    owner.getName().getString(),
                                    tiedPlayer.getName().getString()
                                );
                            } finally {
                                forcedDismountInProgress.remove(
                                    tiedPlayer.getUUID()
                                );
                            }
                        });
                    return;
                }
            }
        }

        // Need captives for Case 2
        if (captorManager == null || !captorManager.hasCaptives()) {
            return;
        }

        // === CASE 2: Empty vehicle → free captive and mount ===
        for (IBondageState captive : captorManager.getCaptives()) {
            LivingEntity captiveEntity = captive.asLivingEntity();

            // Skip if captive is the target itself
            if (captiveEntity == target) continue;

            // Skip if captive already riding something
            if (captiveEntity.isPassenger()) continue;

            // Skip if captive not tied
            if (!captive.isTiedUp()) continue;

            // Free the captive (detaches leash, removes relationship)
            captive.free(true);

            // Mount captive on vehicle (still tied up, can't control)
            boolean success = captiveEntity.startRiding(target, true);

            if (success) {
                TiedUpMod.LOGGER.debug(
                    "[ForcedSeating] {} mounted {} on vehicle",
                    owner.getName().getString(),
                    captive.getKidnappedName()
                );
            }

            event.setCanceled(true);
            return;
        }
    }

    // ========== MOUNT/DISMOUNT EVENTS ==========

    /**
     * Handle mounting/dismounting events.
     * - Block dismount for tied players (unless vehicle is dead)
     * - Swap when owner enters vehicle with tied player
     */
    @SubscribeEvent(priority = EventPriority.HIGHEST)
    public static void onEntityMount(EntityMountEvent event) {
        if (event.getLevel().isClientSide) return;

        Entity rider = event.getEntityMounting();
        Entity vehicle = event.getEntityBeingMounted();

        // === DISMOUNTING ===
        if (event.isDismounting()) {
            if (rider instanceof Player player) {
                // Skip if this is a forced dismount (ALT+click or swap)
                if (
                    forcedDismountInProgress.getOrDefault(
                        player.getUUID(),
                        false
                    )
                ) {
                    return;
                }

                // Furniture manages its own dismount via removePassenger()
                if (
                    vehicle instanceof
                        com.tiedup.remake.v2.furniture.ISeatProvider
                ) {
                    return;
                }

                IBondageState state = KidnappedHelper.getKidnappedState(player);
                if (state != null && state.isTiedUp()) {
                    if (vehicle.isAlive()) {
                        // Block voluntary dismount (Shift key)
                        event.setCanceled(true);
                        SystemMessageManager.sendRestriction(
                            player,
                            MessageCategory.CANT_MOVE
                        );
                        return;
                    }
                    // Vehicle destroyed → captive dismounts, stays free
                }
            }
            return;
        }

        // === MOUNTING: Swap if tied player already in vehicle ===
        if (rider instanceof Player newDriver) {
            // Skip if swap already in progress for this driver
            if (
                forcedDismountInProgress.getOrDefault(
                    newDriver.getUUID(),
                    false
                )
            ) {
                return;
            }

            for (Entity passenger : vehicle.getPassengers()) {
                if (
                    passenger instanceof Player tiedPlayer &&
                    tiedPlayer != newDriver
                ) {
                    IBondageState state = KidnappedHelper.getKidnappedState(
                        tiedPlayer
                    );
                    if (state != null && state.isTiedUp()) {
                        // Mark swap in progress for both players
                        forcedDismountInProgress.put(newDriver.getUUID(), true);
                        forcedDismountInProgress.put(
                            tiedPlayer.getUUID(),
                            true
                        );

                        // Cancel this mount event - we'll do it manually
                        event.setCanceled(true);

                        // Schedule the swap for next tick
                        vehicle
                            .getServer()
                            .execute(() -> {
                                try {
                                    // 1. Dismount tied player
                                    tiedPlayer.stopRiding();

                                    // 2. Mount new driver (becomes controller)
                                    newDriver.startRiding(vehicle, true);

                                    // 3. Remount tied player (becomes passenger)
                                    tiedPlayer.startRiding(vehicle, true);

                                    TiedUpMod.LOGGER.debug(
                                        "[ForcedSeating] Swapped: {} driving, {} passenger",
                                        newDriver.getName().getString(),
                                        tiedPlayer.getName().getString()
                                    );
                                } finally {
                                    forcedDismountInProgress.remove(
                                        newDriver.getUUID()
                                    );
                                    forcedDismountInProgress.remove(
                                        tiedPlayer.getUUID()
                                    );
                                }
                            });
                        return;
                    }
                }
            }
        }
    }
}
