using PkmnLib.Dynamic.Models;
using PkmnLib.Plugin.Gen7.Scripts.Moves;

namespace PkmnLib.Plugin.Gen7.Tests.Scripts.Moves;

/// <summary>
/// Tests for the <see cref="Endeavor"/> move script.
/// Gen VII Bulbapedia behavior: "Endeavor deals damage to the target equal to the target's remaining HP
/// minus the user's remaining HP, making them both equal. It has no effect if the target's HP is already
/// equal to or lower than the user's HP."
/// </summary>
public class EndeavorTests
{
    private static (Endeavor script, IExecutingMove move, IPokemon target) CreateTestSetup(uint userHealth,
        uint targetHealth)
    {
        var script = new Endeavor();
        var move = Substitute.For<IExecutingMove>();
        var user = Substitute.For<IPokemon>();
        user.CurrentHealth.Returns(userHealth);
        move.User.Returns(user);
        var target = Substitute.For<IPokemon>();
        target.CurrentHealth.Returns(targetHealth);
        return (script, move, target);
    }

    /// <summary>
    /// Bulbapedia: "Endeavor deals damage to the target equal to the target's remaining HP minus the
    /// user's remaining HP, making them both equal."
    /// </summary>
    [Test, Arguments(1u, 100u, 99u), Arguments(50u, 100u, 50u), Arguments(99u, 100u, 1u), Arguments(10u, 250u, 240u)]
    public async Task ChangeMoveDamage_UserHpBelowTarget_DamageEqualsHpDifference(uint userHealth, uint targetHealth,
        uint expectedDamage)
    {
        // Arrange
        var (script, move, target) = CreateTestSetup(userHealth, targetHealth);
        var damage = 0u;

        // Act
        script.ChangeMoveDamage(move, target, 0, ref damage);

        // Assert
        await Assert.That(damage).IsEqualTo(expectedDamage);
    }

    /// <summary>
    /// Bulbapedia: "It has no effect if the target's HP is already equal to or lower than the user's HP."
    /// With equal HP the script does not set any damage.
    /// </summary>
    [Test]
    public async Task ChangeMoveDamage_UserHpEqualToTarget_DamageUnchanged()
    {
        // Arrange
        var (script, move, target) = CreateTestSetup(100, 100);
        var damage = 0u;

        // Act
        script.ChangeMoveDamage(move, target, 0, ref damage);

        // Assert
        await Assert.That(damage).IsEqualTo(0u);
    }

    /// <summary>
    /// Bulbapedia: "It has no effect if the target's HP is already equal to or lower than the user's HP."
    /// With the target below the user, the damage is not modified (and does not underflow).
    /// </summary>
    [Test]
    public async Task ChangeMoveDamage_UserHpAboveTarget_DamageUnchanged()
    {
        // Arrange
        var (script, move, target) = CreateTestSetup(100, 50);
        var damage = 0u;

        // Act
        script.ChangeMoveDamage(move, target, 0, ref damage);

        // Assert
        await Assert.That(damage).IsEqualTo(0u);
    }
}