package zenith.zov.utility.entity;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.Vec3d;
import zenith.zov.utility.interfaces.IClient;

public class FakePlayerManager implements IClient {
    private static final FakePlayerManager INSTANCE = new FakePlayerManager();
    private final ConcurrentMap<Integer, FakePlayerEntity> fakePlayers = new ConcurrentHashMap<>();
    private final List<FakePlayerEntity> sandevistanClones = new ArrayList<>();

    private FakePlayerManager() {
    }

    public static FakePlayerManager getInstance() {
        return INSTANCE;
    }

    public FakePlayerEntity createSandevistanClone(PlayerEntity originalEntity) {
        FakePlayerEntity fakePlayer = new FakePlayerEntity(originalEntity, "Sandevistan Clone", true);
        fakePlayer.spawnPlayer();
        this.sandevistanClones.add(fakePlayer);
        this.fakePlayers.put(Integer.valueOf(fakePlayer.getId()), fakePlayer);
        return fakePlayer;
    }

    public FakePlayerEntity createFakePlayer(PlayerEntity originalEntity, String name) {
        FakePlayerEntity fakePlayer = new FakePlayerEntity(originalEntity, name, false);
        fakePlayer.spawnPlayer();
        this.fakePlayers.put(Integer.valueOf(fakePlayer.getId()), fakePlayer);
        return fakePlayer;
    }

    public void removeFakePlayer(FakePlayerEntity fakePlayer) {
        fakePlayer.despawnPlayer();
        this.fakePlayers.remove(Integer.valueOf(fakePlayer.getId()));
        this.sandevistanClones.remove(fakePlayer);
    }

    public void clearAllFakePlayers() {
        for (FakePlayerEntity fakePlayer : this.fakePlayers.values()) {
            fakePlayer.despawnPlayer();
        }

        this.fakePlayers.clear();
        this.sandevistanClones.clear();
    }

    public void cleanupExpiredClones(long maxAge) {
        Iterator<FakePlayerEntity> iterator = this.sandevistanClones.iterator();

        while (iterator.hasNext()) {
            FakePlayerEntity clone = iterator.next();
            if (clone.isExpired(maxAge)) {
                this.removeFakePlayer(clone);
                iterator.remove();
            }
        }
    }

    public void cleanupDistantClones(double maxDistance) {
        if (mc.player != null) {
            Iterator<FakePlayerEntity> iterator = this.sandevistanClones.iterator();

            while (iterator.hasNext()) {
                FakePlayerEntity clone = iterator.next();
                if (!clone.isInRange(maxDistance)) {
                    this.removeFakePlayer(clone);
                    iterator.remove();
                }
            }
        }
    }

    public void updatePositions() {
        for (FakePlayerEntity fakePlayer : this.fakePlayers.values()) {
            if (fakePlayer.getOriginalEntity() != null) {
                fakePlayer.updatePosition(fakePlayer.getOriginalEntity().getPos());
            }
        }
    }

    public List<FakePlayerEntity> getAllFakePlayers() {
        return new ArrayList<>(this.fakePlayers.values());
    }

    public List<FakePlayerEntity> getSandevistanClones() {
        return new ArrayList<>(this.sandevistanClones);
    }

    public FakePlayerEntity getFakePlayer(int id) {
        return this.fakePlayers.get(Integer.valueOf(id));
    }

    public FakePlayerEntity getClosestFakePlayer(Vec3d position) {
        FakePlayerEntity closest = null;
        double closestDistance = Double.MAX_VALUE;

        for (FakePlayerEntity fakePlayer : this.fakePlayers.values()) {
            double distance = fakePlayer.distanceTo(position);
            if (distance < closestDistance) {
                closestDistance = distance;
                closest = fakePlayer;
            }
        }

        return closest;
    }

    public int getFakePlayerCount() {
        return this.fakePlayers.size();
    }

    public int getSandevistanCloneCount() {
        return this.sandevistanClones.size();
    }

    public boolean hasFakePlayer(int id) {
        return this.fakePlayers.containsKey(Integer.valueOf(id));
    }

    public void performCleanup(long maxAge, double maxDistance) {
        this.cleanupExpiredClones(maxAge);
        this.cleanupDistantClones(maxDistance);
        this.updatePositions();
    }
}
