package com.tiedup.remake.items.base;

import com.tiedup.remake.core.SettingsAccessor;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;

/**
 * Interface for bondage items that have a resistance value.
 *
 * <p>The resistance system allows players to "struggle" out of restraints.
 * Higher resistance = more struggle attempts needed to escape.
 *
 * <h2>How Resistance Works</h2>
 * <ol>
 *   <li>Item has a base resistance from config (via SettingsAccessor)</li>
 *   <li>When equipped, current resistance = base resistance</li>
 *   <li>Each struggle attempt decreases current resistance</li>
 *   <li>When current resistance reaches 0, player escapes</li>
 *   <li>Resistance resets when item is unequipped</li>
 * </ol>
 *
 * <h2>Implementations</h2>
 * <ul>
 *   <li>{@link com.tiedup.remake.v2.bondage.items.AbstractV2BondageItem} - All V2 bondage items</li>
 *   <li>{@link com.tiedup.remake.v2.bondage.datadriven.DataDrivenBondageItem} - Data-driven items (resistance via ResistanceComponent)</li>
 * </ul>
 *
 * <p>Based on original IHasResistance.java from 1.12.2
 *
 * @see SettingsAccessor
 */
public interface IHasResistance {
    // NBT KEYS

    /** NBT key for storing current resistance value (camelCase standard) */
    String NBT_CURRENT_RESISTANCE = "currentResistance";

    /** Legacy NBT key for migration from older versions */
    String NBT_CURRENT_RESISTANCE_LEGACY = "currentresistance";

    /** NBT key for storing whether item can be struggled out of */
    String NBT_CAN_STRUGGLE = "canBeStruggledOut";

    // ABSTRACT METHODS (must implement)

    /**
     * Get the item name/ID for resistance config lookup.
     *
     * <p>This is used to look up the base resistance from ModConfig
     * via {@link SettingsAccessor#getBindResistance(String)}.
     *
     * @return Item identifier for resistance lookup
     */
    String getResistanceId();

    /**
     * Called when the entity struggles against this item.
     *
     * <p>Implementations should:
     * <ul>
     *   <li>Play struggle sound</li>
     *   <li>Show message to player</li>
     *   <li>Potentially notify nearby players</li>
     * </ul>
     *
     * @param entity The entity struggling
     */
    void notifyStruggle(LivingEntity entity);

    // DEFAULT METHODS (NBT handling)

    /**
     * Get the base resistance from config via SettingsAccessor.
     *
     * @param entity The entity (kept for API compatibility)
     * @return Base resistance value
     */
    default int getBaseResistance(LivingEntity entity) {
        return SettingsAccessor.getBindResistance(getResistanceId());
    }

    /**
     * Get the current resistance from ItemStack NBT.
     *
     * <p>If no current resistance is stored (or <= 0), returns base resistance.
     * <p>Handles migration from legacy lowercase key to camelCase.
     *
     * @param stack The item stack
     * @param entity The entity (for accessing base resistance)
     * @return Current resistance value
     */
    default int getCurrentResistance(ItemStack stack, LivingEntity entity) {
        if (stack.isEmpty()) {
            return 0;
        }

        CompoundTag tag = stack.getTag();
        if (tag != null) {
            // Check new camelCase key first
            if (tag.contains(NBT_CURRENT_RESISTANCE)) {
                int resistance = tag.getInt(NBT_CURRENT_RESISTANCE);
                if (resistance > 0) {
                    return resistance;
                }
            }
            // Migration: check legacy lowercase key
            else if (tag.contains(NBT_CURRENT_RESISTANCE_LEGACY)) {
                int resistance = tag.getInt(NBT_CURRENT_RESISTANCE_LEGACY);
                // Migrate to new key
                tag.remove(NBT_CURRENT_RESISTANCE_LEGACY);
                if (resistance > 0) {
                    tag.putInt(NBT_CURRENT_RESISTANCE, resistance);
                    return resistance;
                }
            }
        }

        // Default to base resistance
        return getBaseResistance(entity);
    }

    /**
     * Set the current resistance in ItemStack NBT.
     *
     * @param stack The item stack
     * @param resistance The resistance value to set
     * @return The modified item stack
     */
    default ItemStack setCurrentResistance(ItemStack stack, int resistance) {
        if (!stack.isEmpty()) {
            stack.getOrCreateTag().putInt(NBT_CURRENT_RESISTANCE, resistance);
        }
        return stack;
    }

    /**
     * Reset the current resistance (remove from NBT).
     *
     * <p>Called when the item is unequipped. Next time it's equipped,
     * it will start fresh with base resistance.
     *
     * @param stack The item stack
     * @return The modified item stack
     */
    default ItemStack resetCurrentResistance(ItemStack stack) {
        if (!stack.isEmpty()) {
            CompoundTag tag = stack.getTag();
            if (tag != null && tag.contains(NBT_CURRENT_RESISTANCE)) {
                tag.remove(NBT_CURRENT_RESISTANCE);
                // Clean up empty tag
                if (tag.isEmpty()) {
                    stack.setTag(null);
                }
            }
        }
        return stack;
    }

    /**
     * Decrease the current resistance by one struggle attempt.
     *
     * @param stack The item stack
     * @param entity The entity struggling
     * @return The new resistance value after decreasing
     */
    default int decreaseResistance(ItemStack stack, LivingEntity entity) {
        int current = getCurrentResistance(stack, entity);
        int newResistance = Math.max(0, current - 1);
        setCurrentResistance(stack, newResistance);
        return newResistance;
    }

    /**
     * Check if this item can be struggled out of.
     *
     * <p>Some items (like locked collars) cannot be escaped via struggling.
     * Default is true (can be struggled).
     *
     * @param stack The item stack
     * @return True if struggling is allowed
     */
    default boolean canBeStruggledOut(ItemStack stack) {
        if (stack.isEmpty()) {
            return true;
        }

        CompoundTag tag = stack.getTag();
        if (tag != null && tag.contains(NBT_CAN_STRUGGLE)) {
            return tag.getBoolean(NBT_CAN_STRUGGLE);
        }

        return true; // Default: can be struggled
    }

    /**
     * Set whether this item can be struggled out of.
     *
     * @param stack The item stack
     * @param canStruggle True to allow struggling
     * @return The modified item stack
     */
    default ItemStack setCanBeStruggledOut(
        ItemStack stack,
        boolean canStruggle
    ) {
        if (!stack.isEmpty()) {
            stack.getOrCreateTag().putBoolean(NBT_CAN_STRUGGLE, canStruggle);
        }
        return stack;
    }

    /**
     * Check if the entity can escape from this item.
     *
     * <p>Combines struggle permission with current resistance check.
     *
     * @param stack The item stack
     * @param entity The entity trying to escape
     * @return True if escape is possible (resistance = 0 and struggling allowed)
     */
    default boolean canEscape(ItemStack stack, LivingEntity entity) {
        return (
            canBeStruggledOut(stack) && getCurrentResistance(stack, entity) <= 0
        );
    }
}
