package thebetweenlands.common.capability.circlegem;

import java.util.function.Consumer;

import javax.annotation.Nullable;

import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.MobEffects;
import net.minecraft.item.ItemStack;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.DamageSource;
import net.minecraft.util.math.MathHelper;
import thebetweenlands.api.item.IAmphibiousArmorUpgrade;
import thebetweenlands.common.item.armor.amphibious.AmphibiousArmorUpgrades;
import thebetweenlands.common.item.armor.amphibious.ItemAmphibiousArmor;
import thebetweenlands.common.item.misc.ItemGemSinger;

public enum CircleGemType {
	AQUA("aqua", 1, ItemGemSinger.GemSingerTarget.AQUA_MIDDLE_GEM),
	CRIMSON("crimson", 2, ItemGemSinger.GemSingerTarget.CRIMSON_MIDDLE_GEM),
	GREEN("green", 3, ItemGemSinger.GemSingerTarget.GREEN_MIDDLE_GEM),
	NONE("none", 0, null);

	public final String name;
	public final int id;

	@Nullable
	public final ItemGemSinger.GemSingerTarget gemSingerTarget;

	public static final CircleGemType[] TYPES = CircleGemType.values();

	private CircleGemType(String name, int id, ItemGemSinger.GemSingerTarget gemSingerTarget) {
		this.name = name;
		this.id = id;
		this.gemSingerTarget = gemSingerTarget;
	}

	/**
	 * Returns the relation between two gems.
	 * <p>0: Neutral
	 * <p>1: This gem has an advantage over the other gem
	 * <p>-1: This gem has a disadvantage over the other gem
	 * @param gem Circle gem to compare to
	 * @return
	 */
	public int getRelation(CircleGemType gem) {
		switch(this) {
		case CRIMSON:
			switch(gem){
			case GREEN:
				return 1;
			case AQUA:
				return -1;
			default:
				return 0;
			}
		case GREEN:
			switch(gem){
			case AQUA:
				return 1;
			case CRIMSON:
				return -1;
			default:
				return 0;
			}
		case AQUA:
			switch(gem){
			case CRIMSON:
				return 1;
			case GREEN:
				return -1;
			default:
				return 0;
			}
		default:
			return 0;
		}
	}

	/**
	 * Applies the gem proc to the attacker or defender
	 * @param isAttacker Whether the owner is the attacker
	 * @param owner Owner of the gem
	 * @param source The source (damage source, e.g. the entity that shot the projectile)
	 * @param attacker The entity that is actually attacking (can be both the owner himself or a projectile)
	 * @param defender The defending entity
	 * @param strength Proc strength
	 * @param damageSource The damage source
	 * @param damage The damage that was dealt
	 */
	public boolean applyProc(boolean isAttacker, Entity owner, Entity source, Entity attacker, Entity defender, float strength, DamageSource damageSource, float damage) {
		switch(this) {
		case CRIMSON:
			if(isAttacker) {
				if(defender instanceof EntityLivingBase) {
					float knockbackStrength = Math.min(2.5F / 10.0F * (float)strength, 2.5F);
					((EntityLivingBase)defender).knockBack(attacker, knockbackStrength, attacker.posX - defender.posX, attacker.posZ - defender.posZ);
					if(attacker instanceof EntityLivingBase) {
						((EntityLivingBase)attacker).addPotionEffect(new PotionEffect(MobEffects.STRENGTH, 110, Math.min(MathHelper.floor(strength * 0.2F), 2)));
					}
					if(source != attacker && source instanceof EntityLivingBase) {
						((EntityLivingBase)source).addPotionEffect(new PotionEffect(MobEffects.STRENGTH, 110, Math.min(MathHelper.floor(strength * 0.2F), 2)));
					}
					return true;
				}
			} else {
				DamageSource returnedDamageSource;
				if(defender instanceof EntityPlayer) {
					returnedDamageSource = DamageSource.causePlayerDamage((EntityPlayer)defender);
				} else if(defender instanceof EntityLivingBase) {
					returnedDamageSource = DamageSource.causeMobDamage((EntityLivingBase)defender);
				} else {
					returnedDamageSource = DamageSource.GENERIC;
				}
				attacker.attackEntityFrom(returnedDamageSource, Math.min(damage / 16.0F * strength, damage / 1.5F));
				if(source != attacker) {
					source.attackEntityFrom(returnedDamageSource, Math.min(damage / 16.0F * strength, damage / 1.5F));
				}
				return true;
			}
			break;
		case GREEN:
			if(isAttacker) {
				boolean healed = false;
				if(attacker instanceof EntityLivingBase) {
					((EntityLivingBase)attacker).heal(Math.min(Math.max(strength * 0.45F, 1.0F), 10.0F));
					healed = true;
				}
				if(source != attacker && source instanceof EntityLivingBase) {
					((EntityLivingBase)source).heal(Math.min(Math.max(strength * 0.45F, 1.0F), 10.0F));
					healed = true;
				}
				return healed;
			} else {
				if(defender instanceof EntityLivingBase) {
					((EntityLivingBase)defender).addPotionEffect(new PotionEffect(MobEffects.ABSORPTION, 260, Math.min(MathHelper.floor(strength * 0.25F), 2)));
					return true;
				}
			}
			break;
		case AQUA:
			if(isAttacker) {
				if(defender instanceof EntityLivingBase) {
					int amplifier = Math.min(MathHelper.floor(strength * 0.1F), 2);
					switch(amplifier) {
					case 0:
						((EntityLivingBase)defender).addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 80, 0));
						break;
					case 1:
					case 2:
						((EntityLivingBase)defender).addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 40, amplifier));
						break;
					}
					return true;
				}
				break;
			} else {
				if(defender instanceof EntityLivingBase) {
					((EntityLivingBase)defender).addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, 130, Math.min(MathHelper.floor(strength * 0.3F), 2)));
					return true;
				}
			}
			break;
		default:
		}
		return false;
	}

	/**
	 * Returns the gem for the specified name
	 * @param name
	 * @return
	 */
	public static CircleGemType fromName(String name) {
		for(CircleGemType gem : TYPES) {
			if(gem.name.equals(name)) {
				return gem;
			}
		}
		return NONE;
	}

	/**
	 * Returns the gem for the specified ID
	 * @param id
	 * @return
	 */
	public static CircleGemType fromID(int id) {
		for(CircleGemType gem : TYPES) {
			if(gem.id == id) {
				return gem;
			}
		}
		return NONE;
	}

	public final IAmphibiousArmorUpgrade getAmphibiousArmorUpgrade() {
		switch(this) {
		case AQUA:
			return AmphibiousArmorUpgrades.AQUA_GEM;
		case GREEN:
			return AmphibiousArmorUpgrades.GREEN_GEM;
		case CRIMSON:
			return AmphibiousArmorUpgrades.CRIMSON_GEM;
		}
		return null;
	}

	public final Consumer<ItemStack> getAmphibiousArmorOnChangedHandler() {
		return armor -> {
			if(armor.getItem() instanceof ItemAmphibiousArmor) {
				if(((ItemAmphibiousArmor) armor.getItem()).getUpgradeCount(armor, this.getAmphibiousArmorUpgrade()) > 0) {
					CircleGemHelper.setGem(armor, this);
				} else {
					CircleGemHelper.setGem(armor, CircleGemType.NONE);
				}
			}
		};
	}
}
