package org.allaymc.api.item.data;

import org.allaymc.api.entity.effect.EffectInstance;
import org.allaymc.api.entity.effect.EffectTypes;
import org.allaymc.api.entity.interfaces.EntityLiving;

import java.awt.*;
import java.util.List;

/**
 * Represents the various potion types available in the game, including standard potions like
 * Water and Awkward, as well as enhanced potions with effects such as Night Vision, Strength,
 * and Turtle Master.
 * <p>
 * Each potion type can have associated effects, durations, and strengths, which are automatically
 * calculated or defined. Potions with effects also have a color representation that is derived
 * from the colors of their respective effects.
 * <p>
 * Enum constants with no associated effects (e.g., WATER, AWKWARD) represent base or transitional
 * potion states, which are commonly used as ingredients to create other potions.
 *
 * @author daoge_cmd
 */
public enum PotionType {
    WATER,
    MUNDANE,
    LONG_MUNDANE,
    THICK,
    AWKWARD,

    NIGHT_VISION(EffectTypes.NIGHT_VISION.createInstance(0, 3 * 60 * 20)),
    LONG_NIGHT_VISION(EffectTypes.NIGHT_VISION.createInstance(0, 8 * 60 * 20)),

    INVISIBILITY(EffectTypes.INVISIBILITY.createInstance(0, 3 * 60 * 20)),
    LONG_INVISIBILITY(EffectTypes.INVISIBILITY.createInstance(0, 8 * 60 * 20)),

    LEAPING(EffectTypes.JUMP_BOOST.createInstance(0, 3 * 60 * 20)),
    LONG_LEAPING(EffectTypes.JUMP_BOOST.createInstance(0, 8 * 60 * 20)),
    STRONG_LEAPING(EffectTypes.JUMP_BOOST.createInstance(1, 90 * 20)),

    FIRE_RESISTANCE(EffectTypes.FIRE_RESISTANCE.createInstance(0, 3 * 60 * 20)),
    LONG_FIRE_RESISTANCE(EffectTypes.FIRE_RESISTANCE.createInstance(0, 8 * 60 * 20)),

    SWIFTNESS(EffectTypes.SPEED.createInstance(0, 3 * 60 * 20)),
    LONG_SWIFTNESS(EffectTypes.SPEED.createInstance(0, 8 * 60 * 20)),
    STRONG_SWIFTNESS(EffectTypes.SPEED.createInstance(1, 90 * 20)),

    SLOWNESS(EffectTypes.SLOWNESS.createInstance(0, 90 * 20)),
    LONG_SLOWNESS(EffectTypes.SLOWNESS.createInstance(0, 4 * 60 * 20)),

    WATER_BREATHING(EffectTypes.WATER_BREATHING.createInstance(0, 3 * 60 * 20)),
    LONG_WATER_BREATHING(EffectTypes.WATER_BREATHING.createInstance(0, 8 * 60 * 20)),

    HEALING(EffectTypes.INSTANT_HEALTH.createInstance(0, 1)),
    STRONG_HEALING(EffectTypes.INSTANT_HEALTH.createInstance(1, 1)),

    HARMING(EffectTypes.INSTANT_DAMAGE.createInstance(0, 1)),
    STRONG_HARMING(EffectTypes.INSTANT_DAMAGE.createInstance(1, 1)),

    POISON(EffectTypes.POISON.createInstance(0, 45 * 20)),
    LONG_POISON(EffectTypes.POISON.createInstance(0, 2 * 60 * 20)),
    STRONG_POISON(EffectTypes.POISON.createInstance(1, 22 * 20 + 10)), // 22.5s ≈ 22*20+10 ticks

    REGENERATION(EffectTypes.REGENERATION.createInstance(0, 45 * 20)),
    LONG_REGENERATION(EffectTypes.REGENERATION.createInstance(0, 2 * 60 * 20)),
    STRONG_REGENERATION(EffectTypes.REGENERATION.createInstance(1, 22 * 20 + 10)),

    STRENGTH(EffectTypes.STRENGTH.createInstance(0, 3 * 60 * 20)),
    LONG_STRENGTH(EffectTypes.STRENGTH.createInstance(0, 8 * 60 * 20)),
    STRONG_STRENGTH(EffectTypes.STRENGTH.createInstance(1, 90 * 20)),

    WEAKNESS(EffectTypes.WEAKNESS.createInstance(0, 90 * 20)),
    LONG_WEAKNESS(EffectTypes.WEAKNESS.createInstance(0, 4 * 60 * 20)),

    WITHER(EffectTypes.WITHER.createInstance(0, 40 * 20)),

    TURTLE_MASTER(
            EffectTypes.RESISTANCE.createInstance(2, 20 * 20),
            EffectTypes.SLOWNESS.createInstance(3, 20 * 20)
    ),
    LONG_TURTLE_MASTER(
            EffectTypes.RESISTANCE.createInstance(2, 40 * 20),
            EffectTypes.SLOWNESS.createInstance(3, 40 * 20)
    ),
    STRONG_TURTLE_MASTER(
            EffectTypes.RESISTANCE.createInstance(4, 20 * 20),
            EffectTypes.SLOWNESS.createInstance(5, 20 * 20)
    ),

    SLOW_FALLING(EffectTypes.SLOW_FALLING.createInstance(0, 90 * 20)),
    LONG_SLOW_FALLING(EffectTypes.SLOW_FALLING.createInstance(0, 4 * 60 * 20)),

    STRONG_SLOWNESS(EffectTypes.SLOWNESS.createInstance(3, 20 * 20)),

    WIND_CHARGED(EffectTypes.WIND_CHARGED.createInstance(0, 3 * 60 * 20)),
    WEAVING(EffectTypes.WEAVING.createInstance(0, 3 * 60 * 20)),
    OOZING(EffectTypes.OOZING.createInstance(0, 3 * 60 * 20)),
    INFESTED(EffectTypes.INFESTED.createInstance(0, 3 * 60 * 20));

    private static final PotionType[] VALUES = values();

    // This shouldn't be touchable by user code since effect instance is mutable
    private final List<EffectInstance> effects;
    private final Color color;

    PotionType(EffectInstance... effects) {
        this.effects = List.of(effects);
        this.color = computeColor(effects);
    }

    /**
     * Gets the potion type from id.
     *
     * @param id the id of potion
     * @return the potion type
     */
    public static PotionType fromId(int id) {
        return VALUES[id];
    }

    private static Color computeColor(EffectInstance... effects) {
        if (effects.length == 0) {
            // Don't extract it as a constant, because in an enum class the enum member is
            // initialized before the static member, at which point the static member is null
            return new Color(64, 64, 160);
        }

        int r = 0;
        int g = 0;
        int b = 0;
        int count = 0;
        for (var effect : effects) {
            r += effect.getType().getColor().getRed() * effect.getLevel();
            g += effect.getType().getColor().getGreen() * effect.getLevel();
            b += effect.getType().getColor().getBlue() * effect.getLevel();
            count += effect.getLevel();
        }

        return new Color(r / count, g / count, b / count);
    }

    /**
     * Apply this potion type to a specific entity.
     *
     * @param entity the entity that this potion type will be applied to
     */
    public void applyTo(EntityLiving entity) {
        getEffects().forEach(entity::addEffect);
    }

    /**
     * Gets the effects that this potion type has.
     *
     * @return the effects that this potion type has
     */
    public List<EffectInstance> getEffects() {
        return this.effects.stream().map(EffectInstance::new).toList();
    }

    /**
     * Gets the color of this potion type, which is a mix of all effect types that
     * this potion type has.
     *
     * @return the color of this potion type
     */
    public Color getColor() {
        return this.color;
    }
}
