package com.tiedup.remake.items;

import com.tiedup.remake.state.IRestrainable;
import com.tiedup.remake.util.KidnappedHelper;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.ChatFormatting;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.TooltipFlag;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable;

/**

 * GPS Collar - Advanced shock collar with tracking and safe zone features.

 * 

 * <p>Mechanics:</p>

 * <ul>

 *   <li><b>Safe Zones:</b> Can store multiple coordinates (SafeSpots) where the wearer is allowed to be.</li>

 *   <li><b>Auto-Shock:</b> If the wearer is outside ALL active safe zones, they are shocked at intervals.</li>

 *   <li><b>Master Warning:</b> Masters receive an alert message when a safe zone violation is detected.</li>

 *   <li><b>Public Tracking:</b> If enabled, allows anyone with a Locator to see distance and direction.</li>

 * </ul>

 */

public class ItemGpsCollar extends ItemShockCollar {

    private static final String NBT_PUBLIC_TRACKING = "publicTracking";

    private static final String NBT_GPS_ACTIVE = "gpsActive";

    private static final String NBT_SAFE_SPOTS = "gpsSafeSpots";

    private static final String NBT_SHOCK_INTERVAL = "gpsShockInterval";

    private static final String NBT_WARN_MASTERS = "warn_masters";

    private final int defaultInterval;

    public ItemGpsCollar() {
        this(200); // 10 seconds default
    }

    public ItemGpsCollar(int defaultInterval) {
        super();
        this.defaultInterval = defaultInterval;
    }

    @Override
    public boolean hasGPS() {
        return true;
    }

    /**

     * Renders detailed GPS status, safe zone list, and alert settings in the item tooltip.

     */

    @Override
    public void appendHoverText(
        ItemStack stack,
        @Nullable Level level,
        List<Component> tooltip,
        TooltipFlag flag
    ) {
        super.appendHoverText(stack, level, tooltip, flag);

        tooltip.add(
            Component.literal("GPS Enabled").withStyle(
                ChatFormatting.DARK_GREEN
            )
        );

        if (hasPublicTracking(stack)) {
            tooltip.add(
                Component.literal("Public Tracking Enabled").withStyle(
                    ChatFormatting.GREEN
                )
            );
        }

        if (shouldWarnMasters(stack)) {
            tooltip.add(
                Component.literal("Alert Masters on Violation").withStyle(
                    ChatFormatting.GOLD
                )
            );
        }

        List<SafeSpot> safeSpots = getSafeSpots(stack);

        if (!safeSpots.isEmpty()) {
            tooltip.add(
                Component.literal("GPS Shocks: ")
                    .withStyle(ChatFormatting.GREEN)
                    .append(
                        Component.literal(
                            isActive(stack) ? "ENABLED" : "DISABLED"
                        ).withStyle(
                            isActive(stack)
                                ? ChatFormatting.RED
                                : ChatFormatting.GRAY
                        )
                    )
            );

            tooltip.add(
                Component.literal(
                    "Safe Spots (" + safeSpots.size() + "):"
                ).withStyle(ChatFormatting.GREEN)
            );

            for (int i = 0; i < safeSpots.size(); i++) {
                SafeSpot spot = safeSpots.get(i);

                tooltip.add(
                    Component.literal(
                        (spot.active ? "[+] " : "[-] ") +
                            (i + 1) +
                            ": " +
                            spot.x +
                            "," +
                            spot.y +
                            "," +
                            spot.z +
                            " (Range: " +
                            spot.distance +
                            "m)"
                    ).withStyle(ChatFormatting.GRAY)
                );
            }
        }
    }

    public boolean shouldWarnMasters(ItemStack stack) {
        CompoundTag tag = stack.getTag();

        // Default to true if tag doesn't exist

        return (
            tag == null ||
            !tag.contains(NBT_WARN_MASTERS) ||
            tag.getBoolean(NBT_WARN_MASTERS)
        );
    }

    public void setWarnMasters(ItemStack stack, boolean warn) {
        stack.getOrCreateTag().putBoolean(NBT_WARN_MASTERS, warn);
    }

    public boolean hasPublicTracking(ItemStack stack) {
        CompoundTag tag = stack.getTag();

        return tag != null && tag.getBoolean(NBT_PUBLIC_TRACKING);
    }

    public void setPublicTracking(ItemStack stack, boolean publicTracking) {
        stack.getOrCreateTag().putBoolean(NBT_PUBLIC_TRACKING, publicTracking);
    }

    public boolean isActive(ItemStack stack) {
        CompoundTag tag = stack.getTag();

        // Default to active if tag doesn't exist

        return (
            tag == null ||
            !tag.contains(NBT_GPS_ACTIVE) ||
            tag.getBoolean(NBT_GPS_ACTIVE)
        );
    }

    public void setActive(ItemStack stack, boolean active) {
        stack.getOrCreateTag().putBoolean(NBT_GPS_ACTIVE, active);
    }

    /**

     * Parses the NBT List into a Java List of SafeSpot objects.

     */

    public List<SafeSpot> getSafeSpots(ItemStack stack) {
        List<SafeSpot> list = new ArrayList<>();

        CompoundTag tag = stack.getTag();

        if (tag != null && tag.contains(NBT_SAFE_SPOTS)) {
            ListTag spotList = tag.getList(NBT_SAFE_SPOTS, 10);

            for (int i = 0; i < spotList.size(); i++) {
                list.add(new SafeSpot(spotList.getCompound(i)));
            }
        }

        return list;
    }

    /**

     * Adds a new safe zone to the collar's NBT data.

     */

    public void addSafeSpot(
        ItemStack stack,
        int x,
        int y,
        int z,
        String dimension,
        int distance
    ) {
        CompoundTag tag = stack.getOrCreateTag();

        ListTag spotList = tag.getList(NBT_SAFE_SPOTS, 10);

        SafeSpot spot = new SafeSpot(x, y, z, dimension, distance, true);

        spotList.add(spot.toNBT());

        tag.put(NBT_SAFE_SPOTS, spotList);
    }

    /**

     * Gets frequency of GPS violation shocks.

     */

    public int getShockInterval(ItemStack stack) {
        CompoundTag tag = stack.getTag();

        if (tag != null && tag.contains(NBT_SHOCK_INTERVAL)) {
            return tag.getInt(NBT_SHOCK_INTERVAL);
        }

        return defaultInterval;
    }

    /**
     */
    @Override
    public void onUnequipped(ItemStack stack, LivingEntity entity) {
        // Use IRestrainable interface instead of Player-only
        IRestrainable state = KidnappedHelper.getKidnappedState(entity);
        if (state != null) {
            state.resetAutoShockTimer();
        }

        super.onUnequipped(stack, entity);
    }

    /**

     * Represents a defined safe zone in the 3D world.

     */

    public static class SafeSpot {

        public int x, y, z;

        public String dimension;

        public int distance;

        public boolean active;

        public SafeSpot(
            int x,
            int y,
            int z,
            String dimension,
            int distance,
            boolean active
        ) {
            this.x = x;

            this.y = y;

            this.z = z;

            this.dimension = dimension;

            this.distance = distance;

            this.active = active;
        }

        public SafeSpot(CompoundTag nbt) {
            this.x = nbt.getInt("x");

            this.y = nbt.getInt("y");

            this.z = nbt.getInt("z");

            this.dimension = nbt.getString("dim");

            this.distance = nbt.getInt("dist");

            this.active = !nbt.contains("active") || nbt.getBoolean("active");
        }

        public CompoundTag toNBT() {
            CompoundTag nbt = new CompoundTag();

            nbt.putInt("x", x);

            nbt.putInt("y", y);

            nbt.putInt("z", z);

            nbt.putString("dim", dimension);

            nbt.putInt("dist", distance);

            nbt.putBoolean("active", active);

            return nbt;
        }

        /**

         * Checks if an entity is within the cuboid boundaries of this safe zone.

         * Faithful to original 1.12.2 distance logic.

         */

        public boolean isInside(Entity entity) {
            if (!active) return true;

            // LOW FIX: Cross-dimension GPS fix
            // If entity is in a different dimension, consider them as "inside" the zone
            // to prevent false positive shocks when traveling between dimensions
            if (
                !entity
                    .level()
                    .dimension()
                    .location()
                    .toString()
                    .equals(dimension)
            ) return true; // Changed from false to true

            // Cuboid distance check

            return (
                Math.abs(entity.getX() - x) < distance &&
                Math.abs(entity.getY() - y) < distance &&
                Math.abs(entity.getZ() - z) < distance
            );
        }
    }
}
