// 
// Decompiled by Procyon v0.6.0
// 

package com.hypixel.hytale.builtin.adventure.reputation;

import com.hypixel.hytale.server.core.asset.type.attitude.Attitude;
import javax.annotation.Nullable;
import com.hypixel.hytale.component.Store;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerConfigData;
import com.hypixel.hytale.server.core.universe.world.World;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import com.hypixel.hytale.component.ComponentAccessor;
import com.hypixel.hytale.component.Ref;
import com.hypixel.hytale.server.core.entity.entities.Player;
import java.util.logging.Level;
import java.util.Comparator;
import java.util.Collection;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import com.hypixel.hytale.server.core.asset.type.gameplay.GameplayConfig;
import com.hypixel.hytale.codec.Codec;
import com.hypixel.hytale.builtin.adventure.reputation.choices.ReputationRequirement;
import com.hypixel.hytale.server.core.entity.entities.player.pages.choices.ChoiceRequirement;
import com.hypixel.hytale.server.core.command.system.AbstractCommand;
import com.hypixel.hytale.builtin.adventure.reputation.command.ReputationCommand;
import com.hypixel.hytale.builtin.adventure.reputation.assets.ReputationGroup;
import com.hypixel.hytale.assetstore.AssetRegistry;
import java.util.function.Function;
import com.hypixel.hytale.assetstore.codec.AssetCodec;
import com.hypixel.hytale.assetstore.map.DefaultAssetMap;
import com.hypixel.hytale.server.core.asset.HytaleAssetStore;
import javax.annotation.Nonnull;
import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
import com.hypixel.hytale.builtin.adventure.reputation.assets.ReputationRank;
import java.util.List;
import com.hypixel.hytale.builtin.adventure.reputation.store.ReputationDataResource;
import com.hypixel.hytale.component.ResourceType;
import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
import com.hypixel.hytale.component.ComponentType;
import com.hypixel.hytale.server.core.plugin.JavaPlugin;

public class ReputationPlugin extends JavaPlugin
{
    private static ReputationPlugin instance;
    private ComponentType<EntityStore, ReputationGroupComponent> reputationGroupComponentType;
    private ResourceType<EntityStore, ReputationDataResource> reputationDataResourceType;
    private List<ReputationRank> reputationRanks;
    private int maxReputationValue;
    private int minReputationValue;
    public static final int NO_REPUTATION_GROUP = Integer.MIN_VALUE;
    
    public static ReputationPlugin get() {
        return ReputationPlugin.instance;
    }
    
    public ReputationPlugin(@Nonnull final JavaPluginInit init) {
        super(init);
        this.maxReputationValue = Integer.MIN_VALUE;
        this.minReputationValue = Integer.MAX_VALUE;
    }
    
    public ComponentType<EntityStore, ReputationGroupComponent> getReputationGroupComponentType() {
        return this.reputationGroupComponentType;
    }
    
    @Override
    protected void setup() {
        ReputationPlugin.instance = this;
        AssetRegistry.register(((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder(ReputationRank.class, new DefaultAssetMap()).setPath()).setCodec(ReputationRank.CODEC)).setKeyFunction(ReputationRank::getId)).build());
        AssetRegistry.register(((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)((HytaleAssetStore.Builder)HytaleAssetStore.builder(ReputationGroup.class, new DefaultAssetMap()).setPath()).setCodec(ReputationGroup.CODEC)).setKeyFunction(ReputationGroup::getId)).build());
        this.getCommandRegistry().registerCommand(new ReputationCommand());
        ChoiceRequirement.CODEC.register("Reputation", ReputationRequirement.class, ReputationRequirement.CODEC);
        this.reputationDataResourceType = this.getEntityStoreRegistry().registerResource(ReputationDataResource.class, "ReputationData", ReputationDataResource.CODEC);
        this.reputationGroupComponentType = this.getEntityStoreRegistry().registerComponent(ReputationGroupComponent.class, () -> {
            throw new UnsupportedOperationException("Not implemented!");
        });
        GameplayConfig.PLUGIN_CODEC.register(ReputationGameplayConfig.class, "Reputation", ReputationGameplayConfig.CODEC);
    }
    
    @Override
    protected void start() {
        this.reputationRanks = new ObjectArrayList<ReputationRank>(ReputationRank.getAssetMap().getAssetMap().values());
        if (this.reputationRanks.size() <= 1) {
            return;
        }
        this.reputationRanks.sort(Comparator.comparingInt(ReputationRank::getMinValue));
        int previousMaxValue = this.reputationRanks.getFirst().getMaxValue();
        for (int i = 1; i < this.reputationRanks.size(); ++i) {
            final ReputationRank reputationRank = this.reputationRanks.get(i);
            if (previousMaxValue < reputationRank.getMinValue()) {
                this.getLogger().at(Level.WARNING).log("There is a gap between the values of the ReputationRank %s and %s, please review the assets.", reputationRank.getId(), this.reputationRanks.get(i - 1).getId());
            }
            if (previousMaxValue > reputationRank.getMinValue()) {
                this.getLogger().at(Level.WARNING).log("Min value of rank %s is already contained in rank %s, please review the asset.", reputationRank.getId(), this.reputationRanks.get(i - 1).getId());
            }
            previousMaxValue = reputationRank.getMaxValue();
        }
        this.minReputationValue = this.reputationRanks.getFirst().getMinValue();
        this.maxReputationValue = this.reputationRanks.getLast().getMaxValue();
    }
    
    public int changeReputation(@Nonnull final Player player, @Nonnull final Ref<EntityStore> npcRef, final int value, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        final ReputationGroupComponent reputationGroupComponent = componentAccessor.getComponent(npcRef, this.reputationGroupComponentType);
        if (reputationGroupComponent == null) {
            return Integer.MIN_VALUE;
        }
        return this.changeReputation(player, reputationGroupComponent.getReputationGroupId(), value, componentAccessor);
    }
    
    public int changeReputation(@Nonnull final Player player, @Nonnull final String reputationGroupId, final int value, @Nonnull final ComponentAccessor<EntityStore> componentAccessor) {
        final World world = componentAccessor.getExternalData().getWorld();
        final ReputationGameplayConfig reputationGameplayConfig = ReputationGameplayConfig.getOrDefault(world.getGameplayConfig());
        if (reputationGameplayConfig.getReputationStorageType() != ReputationGameplayConfig.ReputationStorageType.PerPlayer) {
            return this.changeReputation(world, reputationGroupId, value);
        }
        final ReputationGroup reputationGroup = ReputationGroup.getAssetMap().getAsset(reputationGroupId);
        if (reputationGroup == null) {
            return Integer.MIN_VALUE;
        }
        final PlayerConfigData playerConfigData = player.getPlayerConfigData();
        final Object2IntOpenHashMap<String> reputationData = new Object2IntOpenHashMap<String>(playerConfigData.getReputationData());
        final int newReputationValue = this.computeReputation(reputationData, reputationGroup, value);
        playerConfigData.setReputationData(reputationData);
        return newReputationValue;
    }
    
    public int changeReputation(@Nonnull final World world, @Nonnull final String reputationGroupId, final int value) {
        final ReputationGameplayConfig reputationGameplayConfig = ReputationGameplayConfig.getOrDefault(world.getGameplayConfig());
        if (reputationGameplayConfig.getReputationStorageType() != ReputationGameplayConfig.ReputationStorageType.PerWorld) {
            return -1;
        }
        final ReputationGroup reputationGroup = ReputationGroup.getAssetMap().getAsset(reputationGroupId);
        if (reputationGroup == null) {
            return Integer.MIN_VALUE;
        }
        final ReputationDataResource reputationDataResource = world.getEntityStore().getStore().getResource(this.reputationDataResourceType);
        return this.computeReputation(reputationDataResource.getReputationStats(), reputationGroup, value);
    }
    
    private int computeReputation(@Nonnull final Object2IntMap<String> reputationData, @Nonnull final ReputationGroup reputationGroup, final int value) {
        return reputationData.compute(reputationGroup.getId(), (k, oldValue) -> {
            final int newValue = (oldValue == null) ? (reputationGroup.getInitialReputationValue() + value) : (oldValue + value);
            return MathUtil.clamp(newValue, this.minReputationValue, this.maxReputationValue - 1);
        });
    }
    
    public int getReputationValue(@Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> playerEntityRef, @Nonnull final Ref<EntityStore> npcEntityRef) {
        final ReputationGroupComponent reputationGroupComponent = store.getComponent(npcEntityRef, this.reputationGroupComponentType);
        if (reputationGroupComponent == null) {
            return Integer.MIN_VALUE;
        }
        return this.getReputationValue(store, playerEntityRef, reputationGroupComponent.getReputationGroupId());
    }
    
    public int getReputationValue(@Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> playerEntityRef, @Nonnull final String reputationGroupId) {
        final World world = store.getExternalData().getWorld();
        final Player playerComponent = store.getComponent(playerEntityRef, Player.getComponentType());
        final ReputationGameplayConfig reputationGameplayConfig = ReputationGameplayConfig.getOrDefault(world.getGameplayConfig());
        if (reputationGameplayConfig.getReputationStorageType() != ReputationGameplayConfig.ReputationStorageType.PerPlayer) {
            return this.getReputationValue(store, reputationGroupId);
        }
        final ReputationGroup reputationGroup = ReputationGroup.getAssetMap().getAsset(reputationGroupId);
        if (reputationGroup != null) {
            final Object2IntMap<String> reputationData = playerComponent.getPlayerConfigData().getReputationData();
            return this.getReputationValueForGroup(reputationData, reputationGroup);
        }
        return Integer.MIN_VALUE;
    }
    
    public int getReputationValue(@Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> npcRef) {
        final String reputationGroupId = store.getComponent(npcRef, this.reputationGroupComponentType).getReputationGroupId();
        return this.getReputationValue(store, reputationGroupId);
    }
    
    public int getReputationValue(@Nonnull final Store<EntityStore> store, final String reputationGroupId) {
        final World world = store.getExternalData().getWorld();
        final ReputationGameplayConfig reputationGameplayConfig = ReputationGameplayConfig.getOrDefault(world.getGameplayConfig());
        if (reputationGameplayConfig.getReputationStorageType() != ReputationGameplayConfig.ReputationStorageType.PerWorld) {
            return Integer.MIN_VALUE;
        }
        final ReputationGroup reputationGroup = ReputationGroup.getAssetMap().getAsset(reputationGroupId);
        if (reputationGroup == null) {
            return Integer.MIN_VALUE;
        }
        final Object2IntMap<String> reputationData = world.getEntityStore().getStore().getResource(this.reputationDataResourceType).getReputationStats();
        return this.getReputationValueForGroup(reputationData, reputationGroup);
    }
    
    private int getReputationValueForGroup(@Nonnull final Object2IntMap<String> reputationData, @Nonnull final ReputationGroup reputationGroup) {
        return reputationData.getOrDefault(reputationGroup.getId(), reputationGroup.getInitialReputationValue());
    }
    
    @Nullable
    public ReputationRank getReputationRank(@Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final Ref<EntityStore> npcRef) {
        final ReputationGroupComponent reputationGroupComponent = store.getComponent(npcRef, this.reputationGroupComponentType);
        if (reputationGroupComponent == null) {
            return null;
        }
        final String reputationGroupId = reputationGroupComponent.getReputationGroupId();
        return this.getReputationRank(store, ref, reputationGroupId);
    }
    
    @Nullable
    public ReputationRank getReputationRank(@Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final String reputationGroupId) {
        final int value = this.getReputationValue(store, ref, reputationGroupId);
        return this.getReputationRankFromValue(value);
    }
    
    @Nullable
    public ReputationRank getReputationRankFromValue(final int value) {
        if (value == Integer.MIN_VALUE) {
            return null;
        }
        for (int i = 0; i < this.reputationRanks.size(); ++i) {
            if (this.reputationRanks.get(i).containsValue(value)) {
                return this.reputationRanks.get(i);
            }
        }
        return null;
    }
    
    @Nullable
    public ReputationRank getReputationRank(@Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> npcRef) {
        final World world = store.getExternalData().getWorld();
        final ReputationGameplayConfig reputationGameplayConfig = ReputationGameplayConfig.getOrDefault(world.getGameplayConfig());
        if (reputationGameplayConfig.getReputationStorageType() != ReputationGameplayConfig.ReputationStorageType.PerWorld) {
            return null;
        }
        final int value = this.getReputationValue(store, npcRef);
        return this.getReputationRankFromValue(value);
    }
    
    @Nullable
    public Attitude getAttitude(@Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> ref, @Nonnull final Ref<EntityStore> npc) {
        final ReputationRank reputationRank = this.getReputationRank(store, ref, npc);
        return (reputationRank != null) ? reputationRank.getAttitude() : null;
    }
    
    @Nullable
    public Attitude getAttitude(@Nonnull final Store<EntityStore> store, @Nonnull final Ref<EntityStore> npcRef) {
        final ReputationRank reputationRank = this.getReputationRank(store, npcRef);
        return (reputationRank != null) ? reputationRank.getAttitude() : null;
    }
}
