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

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

/// <summary>
/// Tests for the <see cref="CrushGrip"/> move script.
/// Gen VII Bulbapedia behavior: "Crush Grip deals damage. Its power is greater the more HP the target
/// has." Power = 120 × (Current HP target / Max HP target), with a minimum of 1.
/// </summary>
public class CrushGripTests
{
    private static (CrushGrip script, IExecutingMove move, IPokemon target) CreateTestSetup(uint currentHealth,
        uint maxHealth)
    {
        var script = new CrushGrip();
        var move = Substitute.For<IExecutingMove>();
        var target = Substitute.For<IPokemon>();
        target.CurrentHealth.Returns(currentHealth);
        target.BoostedStats.Returns(new StatisticSet<uint>(maxHealth, 1, 1, 1, 1, 1));
        return (script, move, target);
    }

    /// <summary>
    /// Bulbapedia: "Power = 120 × (Current HP target / Max HP target)" — at full HP the power is 120, and
    /// it scales down (with integer truncation) as the target's HP drops.
    /// </summary>
    [Test, Arguments(100u, 100u, (ushort)120), Arguments(200u, 200u, (ushort)120), Arguments(50u, 100u, (ushort)60),
     Arguments(75u, 100u, (ushort)90), Arguments(33u, 100u, (ushort)39), Arguments(1u, 4u, (ushort)30)]
    public async Task ChangeBasePower_ScalesWithTargetCurrentHp(uint currentHealth, uint maxHealth,
        ushort expectedPower)
    {
        // Arrange
        var (script, move, target) = CreateTestSetup(currentHealth, maxHealth);
        ushort basePower = 120;

        // Act
        script.ChangeBasePower(move, target, 0, ref basePower);

        // Assert
        await Assert.That(basePower).IsEqualTo(expectedPower);
    }

    /// <summary>
    /// Bulbapedia: the power varies "between 1 and 120 [...] with a minimum of 1" — even against a target
    /// with almost no HP left, the power cannot drop below 1.
    /// </summary>
    [Test, Arguments(1u, 200u), Arguments(1u, 121u)]
    public async Task ChangeBasePower_TargetAtVeryLowHp_PowerIsAtLeastOne(uint currentHealth, uint maxHealth)
    {
        // Arrange
        var (script, move, target) = CreateTestSetup(currentHealth, maxHealth);
        ushort basePower = 120;

        // Act
        script.ChangeBasePower(move, target, 0, ref basePower);

        // Assert
        await Assert.That(basePower).IsEqualTo((ushort)1);
    }
}