package com.tiedup.remake.state;

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.v2.BodyRegionV2;
import com.tiedup.remake.v2.bondage.CollarHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;

// C6-V2: IRestrainable → IBondageState (narrowed API)

/**
 *
 * Manages capture relationships for player captors.
 *
 * Terminology:
 * - "Captive" = Entity attached by leash (active physical control)
 * - "Slave" = Entity wearing a collar owned by someone (passive ownership via CollarRegistry)
 *
 * Features:
 * - Supports multiple captives simultaneously
 * - Allows captive transfer between captors
 * - Tracks captive list persistently
 * - Handles cleanup on captive logout/escape
 *
 * Thread Safety:
 * - Uses CopyOnWriteArrayList to avoid ConcurrentModificationException
 * - Safe for iteration during modification
 *
 * Design:
 * - Each PlayerBindState has one PlayerCaptorManager
 * - Manager tracks all captives owned by that player
 * - Implements ICaptor interface for polymorphic usage
 *
 * @see ICaptor
 * @see PlayerBindState
 */
public class PlayerCaptorManager implements ICaptor {

    /**
     * The player who owns this manager (the captor).
     */
    private final Player captor;

    /**
     * List of all captives currently owned by this captor.
     * Thread-safe to avoid concurrent modification during iteration.
     *
     */
    private final List<IBondageState> captives;

    /**
     * Create a new captor manager for the given player.
     *
     * @param captor The player who will be the captor
     */
    public PlayerCaptorManager(Player captor) {
        this.captor = captor;
        this.captives = new CopyOnWriteArrayList<>();
    }

    // ICaptor Implementation

    /**
     */
    @Override
    public synchronized void addCaptive(IBondageState captive) {
        if (captive == null) {
            TiedUpMod.LOGGER.warn(
                "[PlayerCaptorManager] Attempted to add null captive"
            );
            return;
        }

        if (!captives.contains(captive)) {
            captives.add(captive);
            TiedUpMod.LOGGER.info(
                "[PlayerCaptorManager] {} captured {} (total captives: {})",
                captor.getName().getString(),
                captive.getKidnappedName(),
                captives.size()
            );
        }
    }

    /**
     *
     * Thread Safety: Synchronized on 'this' to match addCaptive and freeAllCaptives.
     */
    @Override
    public synchronized void removeCaptive(
        IBondageState captive,
        boolean transportState
    ) {
        if (captive == null) {
            TiedUpMod.LOGGER.warn(
                "[PlayerCaptorManager] Attempted to remove null captive"
            );
            return;
        }

        if (captives.remove(captive)) {
            TiedUpMod.LOGGER.info(
                "[PlayerCaptorManager] {} freed {} (remaining captives: {})",
                captor.getName().getString(),
                captive.getKidnappedName(),
                captives.size()
            );

            // If requested, also despawn the transport entity
            if (transportState && captive.getTransport() != null) {
                captive.getTransport().discard();
            }
        }
    }

    /**
     */
    @Override
    public boolean canCapture(IBondageState target) {
        if (target == null) {
            return false;
        }

        // From original code (PlayerBindState.java:195-225):
        // Can capture if:
        // - Target is tied up, OR
        // - Target has collar AND collar has this captor as owner

        net.minecraft.world.entity.LivingEntity targetEntity =
            target.asLivingEntity();
        if (targetEntity == null) {
            return false;
        }

        // Check if target is tied up
        if (target.isTiedUp()) {
            return true;
        }

        // Check if target has collar with this captor as owner
        if (target.hasCollar()) {
            ItemStack collar = target.getEquipment(BodyRegionV2.NECK);
            if (CollarHelper.isCollar(collar)) {
                if (
                    CollarHelper.getOwners(collar).contains(this.captor.getUUID())
                ) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     */
    @Override
    public boolean canRelease(IBondageState captive) {
        if (captive == null) {
            return false;
        }

        // Can only release if this manager is the captive's captor
        return captive.getCaptor() == this;
    }

    /**
     */
    @Override
    public boolean allowCaptiveTransfer() {
        // Players always allow captive transfer
        return true;
    }

    /**
     */
    @Override
    public boolean allowMultipleCaptives() {
        // Players can have multiple captives
        return true;
    }

    /**
     * Note: For NPC captives, this is never called (NPCs don't log out)
     */
    @Override
    public void onCaptiveLogout(IBondageState captive) {
        if (captive == null) {
            return;
        }

        TiedUpMod.LOGGER.info(
            "[PlayerCaptorManager] Captive {} logged out while captured by {}",
            captive.getKidnappedName(),
            captor.getName().getString()
        );

        // Keep captive in list - they might reconnect
        // Transport entity will despawn after timeout
        // On reconnect, checkStillCaptive() will clean up if needed
    }

    /**
     */
    @Override
    public void onCaptiveReleased(IBondageState captive) {
        if (captive == null) {
            return;
        }

        TiedUpMod.LOGGER.info(
            "[PlayerCaptorManager] Captive {} was released from {}",
            captive.getKidnappedName(),
            captor.getName().getString()
        );

        // No special action needed - already removed from list by removeCaptive()
    }

    /**
     */
    @Override
    public void onCaptiveStruggle(IBondageState captive) {
        if (captive == null) {
            return;
        }

        TiedUpMod.LOGGER.debug(
            "[PlayerCaptorManager] Captive {} struggled (captor: {})",
            captive.getKidnappedName(),
            captor.getName().getString()
        );
    }

    /**
     */
    @Override
    public boolean hasCaptives() {
        return !captives.isEmpty();
    }

    @Override
    public Entity getEntity() {
        return captor;
    }

    // Additional Methods

    /**
     * Frees all captives currently owned by this captor.
     *
     *
     * Thread Safety: Synchronized on 'this' to match addCaptive and removeCaptive.
     *
     * @param transportState If true, destroy the transporter entities
     */
    public synchronized void freeAllCaptives(boolean transportState) {
        // Use a copy to avoid concurrent modification while iterating
        List<IBondageState> copy = new ArrayList<>(captives);
        for (IBondageState captive : copy) {
            captive.free(transportState);
        }
        captives.clear();
    }

    /**
     * Frees all captives with default behavior (destroy transport entities).
     */
    public void freeAllCaptives() {
        freeAllCaptives(true);
    }

    /**
     * Get a copy of the captive list.
     * Safe for iteration without concurrent modification issues.
     *
     *
     * @return Copy of the current captive list
     */
    public List<IBondageState> getCaptives() {
        return new ArrayList<>(captives);
    }

    /**
     * Get the number of captives currently owned.
     *
     *
     * @return Captive count
     */
    public int getCaptiveCount() {
        return captives.size();
    }

    /**
     * Transfer all captives from this captor to a new captor.
     * Used when this player gets captured themselves.
     *
     * From original code:
     * - When a player gets captured, their captives transfer to new captor
     * - Prevents circular capture issues
     *
     *
     * @param newCaptor The new captor to transfer captives to
     */
    public void transferAllCaptivesTo(ICaptor newCaptor) {
        if (newCaptor == null) {
            TiedUpMod.LOGGER.warn(
                "[PlayerCaptorManager] Attempted to transfer captives to null captor"
            );
            return;
        }

        if (captives.isEmpty()) {
            return;
        }

        TiedUpMod.LOGGER.info(
            "[PlayerCaptorManager] Transferring {} captives from {} to {}",
            captives.size(),
            captor.getName().getString(),
            newCaptor.getEntity().getName().getString()
        );

        // Create copy to avoid concurrent modification
        List<IBondageState> captivesToTransfer = new ArrayList<>(captives);

        for (IBondageState captive : captivesToTransfer) {
            if (captive != null) {
                captive.transferCaptivityTo(newCaptor);
            }
        }

        // All captives should now be removed from this manager's list
        if (!captives.isEmpty()) {
            TiedUpMod.LOGGER.warn(
                "[PlayerCaptorManager] {} captives remain after transfer - cleaning up",
                captives.size()
            );
            captives.clear();
        }
    }

    /**
     * Get the captor player.
     *
     * @return The player who owns this manager
     */
    public Player getCaptor() {
        return captor;
    }

    /**
     * Clean up invalid captives from the list.
     * Removes captives that are no longer valid (offline, transport gone, etc.).
     *
     *
     * Should be called periodically (e.g., on tick).
     */
    public void cleanupInvalidCaptives() {
        captives.removeIf(captive -> {
            if (captive == null) {
                return true;
            }

            // Remove if not actually captured anymore
            if (!captive.isCaptive()) {
                TiedUpMod.LOGGER.debug(
                    "[PlayerCaptorManager] Removing invalid captive {}",
                    captive.getKidnappedName()
                );
                return true;
            }

            // Remove if captured by different captor
            if (captive.getCaptor() != this) {
                TiedUpMod.LOGGER.debug(
                    "[PlayerCaptorManager] Removing captive {} (belongs to different captor)",
                    captive.getKidnappedName()
                );
                return true;
            }

            return false;
        });
    }

    // Backward Compatibility
}
