package com.tiedup.remake.prison.service;

import com.tiedup.remake.core.TiedUpMod;
import com.tiedup.remake.state.IBondageState;
import com.tiedup.remake.v2.BodyRegionV2;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;

/**
 * Centralized bondage state management.
 *
 * Handles saving/restoring bondage state for labor extraction.
 * When a prisoner is extracted for labor, their restraints are temporarily removed.
 * When they return, the original restraints are restored.
 */
public class BondageService {

    // Singleton instance
    private static final BondageService INSTANCE = new BondageService();

    public static BondageService get() {
        return INSTANCE;
    }

    private BondageService() {}

    // ==================== SNAPSHOT ====================

    /**
     * Save the prisoner's current bondage state before extraction.
     * Captures all restraints EXCEPT the collar (which must never be removed).
     *
     * @param cap The prisoner's kidnapped capability
     * @return CompoundTag containing the snapshot
     */
    public CompoundTag saveSnapshot(IBondageState cap) {
        CompoundTag tag = new CompoundTag();

        // Save bind/tie state
        if (cap.isTiedUp()) {
            ItemStack bind = cap.getEquipment(BodyRegionV2.ARMS);
            if (!bind.isEmpty()) {
                tag.put("BindItem", bind.save(new CompoundTag()));
                TiedUpMod.LOGGER.debug(
                    "[BondageService] SAVE: BindItem = {}",
                    bind.getItem().getDescriptionId()
                );
            }
        }

        // Save gag state
        if (cap.isGagged()) {
            ItemStack gag = cap.getEquipment(BodyRegionV2.MOUTH);
            if (!gag.isEmpty()) {
                tag.put("GagItem", gag.save(new CompoundTag()));
                TiedUpMod.LOGGER.debug(
                    "[BondageService] SAVE: GagItem = {}",
                    gag.getItem().getDescriptionId()
                );
            }
        }

        // Save blindfold state
        tag.putBoolean("Blindfolded", cap.isBlindfolded());
        if (cap.isBlindfolded()) {
            ItemStack blindfold = cap.getEquipment(BodyRegionV2.EYES);
            if (!blindfold.isEmpty()) {
                tag.put("BlindfoldItem", blindfold.save(new CompoundTag()));
            }
        }

        // Save mittens state
        tag.putBoolean("HasMittens", cap.hasMittens());
        if (cap.hasMittens()) {
            ItemStack mittens = cap.getEquipment(BodyRegionV2.HANDS);
            if (!mittens.isEmpty()) {
                tag.put("MittensItem", mittens.save(new CompoundTag()));
            }
        }

        // Save earplugs state
        tag.putBoolean("HasEarplugs", cap.hasEarplugs());
        if (cap.hasEarplugs()) {
            ItemStack earplugs = cap.getEquipment(BodyRegionV2.EARS);
            if (!earplugs.isEmpty()) {
                tag.put("EarplugsItem", earplugs.save(new CompoundTag()));
            }
        }

        TiedUpMod.LOGGER.debug(
            "[BondageService] SAVE complete: keys={}",
            tag.getAllKeys()
        );

        // NOTE: Collar is NEVER saved - it's invariant and must stay on
        return tag;
    }

    /**
     * Restore the prisoner's bondage state after labor completion.
     * Reapplies all restraints that were saved EXCEPT the collar.
     *
     * @param cap The prisoner's kidnapped capability
     * @param snapshot The saved bondage snapshot
     */
    public void restoreSnapshot(IBondageState cap, CompoundTag snapshot) {
        if (snapshot == null || snapshot.isEmpty()) {
            TiedUpMod.LOGGER.warn(
                "[BondageService] RESTORE: snapshot is NULL or empty - nothing to restore!"
            );
            return;
        }

        TiedUpMod.LOGGER.debug(
            "[BondageService] RESTORE: Starting restore, keys={}",
            snapshot.getAllKeys()
        );

        // Restore bind/tie
        if (snapshot.contains("BindItem")) {
            ItemStack bind = ItemStack.of(snapshot.getCompound("BindItem"));
            if (!bind.isEmpty()) {
                cap.equip(BodyRegionV2.ARMS, bind);
                TiedUpMod.LOGGER.debug(
                    "[BondageService] RESTORE: Applied BindItem = {}",
                    bind.getItem().getDescriptionId()
                );
            }
        }

        // Restore gag
        if (snapshot.contains("GagItem")) {
            ItemStack gag = ItemStack.of(snapshot.getCompound("GagItem"));
            if (!gag.isEmpty()) {
                cap.equip(BodyRegionV2.MOUTH, gag);
                TiedUpMod.LOGGER.debug(
                    "[BondageService] RESTORE: Applied GagItem = {}",
                    gag.getItem().getDescriptionId()
                );
            }
        }

        // Restore blindfold
        if (
            snapshot.getBoolean("Blindfolded") &&
            snapshot.contains("BlindfoldItem")
        ) {
            ItemStack blindfold = ItemStack.of(
                snapshot.getCompound("BlindfoldItem")
            );
            if (!blindfold.isEmpty()) {
                cap.equip(BodyRegionV2.EYES, blindfold);
            }
        }

        // Restore mittens
        if (
            snapshot.getBoolean("HasMittens") &&
            snapshot.contains("MittensItem")
        ) {
            ItemStack mittens = ItemStack.of(
                snapshot.getCompound("MittensItem")
            );
            if (!mittens.isEmpty()) {
                cap.equip(BodyRegionV2.HANDS, mittens);
            }
        }

        // Restore earplugs
        if (
            snapshot.getBoolean("HasEarplugs") &&
            snapshot.contains("EarplugsItem")
        ) {
            ItemStack earplugs = ItemStack.of(
                snapshot.getCompound("EarplugsItem")
            );
            if (!earplugs.isEmpty()) {
                cap.equip(BodyRegionV2.EARS, earplugs);
            }
        }

        // NOTE: Collar is NEVER restored - it's invariant and already on
    }

    /**
     * Remove temporary bondage restraints for labor.
     * Called after saveSnapshot() to free the prisoner's hands for work.
     *
     * @param cap The prisoner's kidnapped capability
     */
    public void removeForLabor(IBondageState cap) {
        // Remove bind (so they can use hands)
        if (cap.isTiedUp()) {
            cap.unequip(BodyRegionV2.ARMS);
        }

        // Remove gag (so they can communicate if needed)
        if (cap.isGagged()) {
            cap.unequip(BodyRegionV2.MOUTH);
        }

        // Remove blindfold (so they can see)
        if (cap.isBlindfolded()) {
            cap.unequip(BodyRegionV2.EYES);
        }

        // Remove mittens (so they can use hands)
        if (cap.hasMittens()) {
            cap.unequip(BodyRegionV2.HANDS);
        }

        // Remove earplugs (guards need to communicate with the prisoner)
        if (cap.hasEarplugs()) {
            cap.unequip(BodyRegionV2.EARS);
        }

        // NOTE: Collar ALWAYS stays on - never remove it

        TiedUpMod.LOGGER.debug("[BondageService] Removed restraints for labor");
    }

    /**
     * Check if a player has any restraints that would impede labor.
     */
    public boolean hasLaborImpedingRestraints(IBondageState cap) {
        return cap.isTiedUp() || cap.isBlindfolded() || cap.hasMittens();
    }

    /**
     * Apply basic prisoner restraints (bind only).
     * Used when initially imprisoning a captive.
     */
    public void applyBasicRestraints(IBondageState cap, ItemStack rope) {
        if (!cap.isTiedUp() && !rope.isEmpty()) {
            cap.equip(BodyRegionV2.ARMS, rope.copy());
        }
    }

    /**
     * Apply full restraints for cell confinement.
     * Typically includes bind + gag.
     */
    public void applyFullRestraints(
        IBondageState cap,
        ItemStack bind,
        ItemStack gag
    ) {
        if (!cap.isTiedUp() && !bind.isEmpty()) {
            cap.equip(BodyRegionV2.ARMS, bind.copy());
        }
        if (!cap.isGagged() && gag != null && !gag.isEmpty()) {
            cap.equip(BodyRegionV2.MOUTH, gag.copy());
        }
    }
}
