/*
 * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight)
 * by the Epic Fight Team, licensed under GPLv3.
 * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
 */

package com.tiedup.remake.rig.patch;

import java.util.Optional;

import javax.annotation.Nullable;

import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.common.capabilities.CapabilityToken;

/**
 * Holder du {@link Capability} central RIG, analogue à EF
 * {@code yesman.epicfight.world.capabilities.EpicFightCapabilities} mais réduit
 * à l'essentiel pour TiedUp :
 *
 * <ul>
 *   <li>{@link #CAPABILITY_ENTITY} — attaché à {@code Player} (Phase 2) et NPCs
 *       TiedUp (Phase 5). Porte l'{@link EntityPatch} qui contient l'Animator,
 *       l'Armature, l'état d'animation, etc.</li>
 * </ul>
 *
 * <p>EF a également {@code CAPABILITY_ITEM}, {@code CAPABILITY_PROJECTILE},
 * {@code CAPABILITY_SKILL} — tous combat-only, strippés pour TiedUp.</p>
 *
 * <p><b>Auto-registration</b> : {@link CapabilityToken} utilise une TypeToken
 * pour enregistrer le capability via réflection. Pas besoin d'abonner un
 * {@code RegisterCapabilitiesEvent} (comportement Forge 1.20.1, déjà utilisé
 * pour {@code V2_BONDAGE_EQUIPMENT} dans TiedUp).</p>
 */
@SuppressWarnings("rawtypes")
public class TiedUpCapabilities {

	public static final Capability<EntityPatch> CAPABILITY_ENTITY =
		CapabilityManager.get(new CapabilityToken<>() {});

	private TiedUpCapabilities() {}

	/**
	 * Extrait l'{@link EntityPatch} d'un entity avec null-check + type-check.
	 *
	 * @return le patch cast au type demandé, ou null si entity null / pas de
	 *         capability / type incompatible
	 */
	@SuppressWarnings("unchecked")
	@Nullable
	public static <T extends EntityPatch> T getEntityPatch(@Nullable Entity entity, Class<T> type) {
		if (entity == null) {
			return null;
		}
		EntityPatch<?> patch = entity.getCapability(CAPABILITY_ENTITY).orElse(null);
		if (patch != null && type.isAssignableFrom(patch.getClass())) {
			return (T) patch;
		}
		return null;
	}

	/**
	 * Helper court pour extraire un {@link PlayerPatch} d'un {@link Player}.
	 */
	@Nullable
	public static PlayerPatch<?> getPlayerPatch(@Nullable Player player) {
		if (player == null) {
			return null;
		}
		EntityPatch<?> patch = player.getCapability(CAPABILITY_ENTITY).orElse(null);
		return patch instanceof PlayerPatch<?> pp ? pp : null;
	}

	/**
	 * Version {@link Optional} de {@link #getPlayerPatch(Player)} pour les
	 * call sites qui veulent un flow {@code .ifPresent(...)}.
	 */
	public static Optional<PlayerPatch<?>> getPlayerPatchAsOptional(@Nullable Entity entity) {
		if (entity == null) {
			return Optional.empty();
		}
		EntityPatch<?> patch = entity.getCapability(CAPABILITY_ENTITY).orElse(null);
		return patch instanceof PlayerPatch<?> pp ? Optional.of(pp) : Optional.empty();
	}
}
