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="ElectroBall"/> move script.
/// Gen VII Bulbapedia behavior: "Electro Ball inflicts more damage the faster the user is compared to the
/// target." The power is based on the target's Speed as a percentage of the user's Speed:
/// more than 100% (or exactly 0) → 40, 50.01%–100% → 60, 33.34%–50% → 80, 25.01%–33.33% → 120,
/// 0.01%–25% → 150. "The Speed values used take all modifiers into account (including stat stages,
/// paralysis, held items [...], and Abilities [...])."
/// </summary>
public class ElectroBallTests
{
    private static (ElectroBall script, IExecutingMove move, IPokemon target) CreateTestSetup(uint userSpeed,
        uint targetSpeed)
    {
        var script = new ElectroBall();
        var move = Substitute.For<IExecutingMove>();
        var user = Substitute.For<IPokemon>();
        user.BoostedStats.Returns(new StatisticSet<uint>(1, 1, 1, 1, 1, userSpeed));
        move.User.Returns(user);
        var target = Substitute.For<IPokemon>();
        target.BoostedStats.Returns(new StatisticSet<uint>(1, 1, 1, 1, 1, targetSpeed));
        return (script, move, target);
    }

    /// <summary>
    /// Bulbapedia: the power scales with the target's Speed as a percentage of the user's Speed —
    /// more than 100% → 40, 50.01%–100% → 60, 33.34%–50% → 80, 25.01%–33.33% → 120, 0.01%–25% → 150.
    /// </summary>
    [Test, Arguments(100u, 150u, (ushort)40), Arguments(100u, 101u, (ushort)40), Arguments(100u, 70u, (ushort)60),
     Arguments(100u, 40u, (ushort)80), Arguments(100u, 30u, (ushort)120), Arguments(100u, 20u, (ushort)150),
     Arguments(500u, 100u, (ushort)150)]
    public async Task ChangeBasePower_ScalesWithSpeedRatio(uint userSpeed, uint targetSpeed, ushort expectedPower)
    {
        // Arrange
        var (script, move, target) = CreateTestSetup(userSpeed, targetSpeed);
        ushort basePower = 40;

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

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

    /// <summary>
    /// Bulbapedia: the power bands are inclusive of their upper boundary — a target at exactly 100% of the
    /// user's Speed yields 60 power, exactly 50% yields 80, exactly 33.33% yields 120, and exactly 25%
    /// yields 150.
    /// </summary>
    [Test, Arguments(100u, 100u, (ushort)60), Arguments(100u, 50u, (ushort)80), Arguments(300u, 100u, (ushort)120),
     Arguments(400u, 100u, (ushort)150)]
    public async Task ChangeBasePower_SpeedRatioAtExactBoundary_UsesHigherTier(uint userSpeed, uint targetSpeed,
        ushort expectedPower)
    {
        // Arrange
        var (script, move, target) = CreateTestSetup(userSpeed, targetSpeed);
        ushort basePower = 40;

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

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

    /// <summary>
    /// Bulbapedia: the power is 40 when the target's Speed is "more than 100%, or exactly 0" of the
    /// user's Speed.
    /// </summary>
    [Test]
    public async Task ChangeBasePower_TargetSpeedZero_PowerIsForty()
    {
        // Arrange
        var (script, move, target) = CreateTestSetup(100, 0);
        ushort basePower = 40;

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

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