using PkmnLib.Dynamic.Models;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Plugin.Gen7.Libraries.Battling;
using PkmnLib.Static;
using PkmnLib.Static.Moves;

namespace PkmnLib.Plugin.Gen7.Tests;

public class DamageCalculatorTests
{
    /// <summary>
    /// Implements the following example from Bulbapedia:
    /// </summary>
    /// <para>
    /// Imagine a level 75 Glaceon that does not suffer a burn and holds no item with an effective Attack stat of 123
    /// uses Ice Fang (an Ice-type physical move with a power of 65) against a Garchomp with an effective Defense stat
    /// of 163 in Generation VI, and does not land a critical hit. Then, the move will receive STAB, because Glaceon's
    /// Ice type matches the move's: STAB = 1.5. Additionally, Garchomp is Dragon/Ground, and therefore has a double
    /// weakness to the move's Ice type: Type = 4. All other (non-random) modifiers will be 1.
    ///
    /// That means Ice Fang will do between 168 and 196 HP damage, depending on luck. 
    /// </para>
    [Test]
    public async Task BulbapediaExampleDamageTest()
    {
        var attacker = Substitute.For<IPokemon>();
        // Imagine a level 75 Glaceon
        attacker.Level.Returns((byte)75);
        // with an effective Attack stat of 123
        attacker.BoostedStats.Returns(new StatisticSet<uint>(1, 123, 1, 1, 1, 1));
        // We use 10 as the Ice type
        attacker.Types.Returns([new TypeIdentifier(10, "ice")]);

        var defender = Substitute.For<IPokemon>();
        // a Garchomp with an effective Defense stat of 163
        defender.BoostedStats.Returns(new StatisticSet<uint>(1, 1, 163, 1, 1, 1));
        defender.GetScripts().Returns(new ScriptIterator([]));

        var useMove = Substitute.For<IMoveData>();
        // Ice Fang (an Ice-type physical move with a power of 65)
        useMove.Category.Returns(MoveCategory.Physical);

        var damageCalculator = new Gen7DamageCalculator(new Gen7PluginConfiguration
        {
            DamageCalculatorHasRandomness = false,
        });
        var executingMove = Substitute.For<IExecutingMove>();
        executingMove.UseMove.Returns(useMove);
        executingMove.User.Returns(attacker);
        executingMove.GetScripts().Returns(new ScriptIterator([]));

        var hit = Substitute.For<IHitData>();
        // Ice Fang (an Ice-type physical move with a power of 65)
        hit.BasePower.Returns((byte)65);
        hit.Type.Returns(new TypeIdentifier(10, "ice"));
        // has a double weakness to the move's Ice type
        hit.Effectiveness.Returns(4.0f);

        var damage = damageCalculator.GetDamage(executingMove, executingMove.UseMove.Category, executingMove.User,
            defender, executingMove.TargetCount, 0, hit);
        // That means Ice Fang will do between 168 and 196 HP damage, depending on luck.
        // Note that we are testing deterministic damage, so we expect the maximum damage.
        await Assert.That(damage).IsEqualTo((uint)196);
    }
}