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="Covet"/> move script.
/// Gen VII Bulbapedia behavior: "Covet inflicts damage and steals the target's held item if it is holding
/// any. If the target is not holding an item or the user is already holding an item, Covet cannot steal an
/// item."
/// </summary>
public class CovetTests
{
    private static (Covet script, IExecutingMove move, IPokemon user, IPokemon target) CreateTestSetup(
        IItem? targetItem)
    {
        var script = new Covet();
        var move = Substitute.For<IExecutingMove>();
        var user = Substitute.For<IPokemon>();
        // Explicitly return null to suppress NSubstitute's auto-substitution; Covet must see an empty-handed user.
        user.HeldItem.Returns((IItem?)null);
        move.User.Returns(user);

        var target = Substitute.For<IPokemon>();
        target.HeldItem.Returns(targetItem);
        if (targetItem != null)
        {
            target.TryStealHeldItem(out Arg.Any<IItem?>()).Returns(x =>
            {
                x[0] = targetItem;
                return true;
            });
        }

        return (script, move, user, target);
    }

    /// <summary>
    /// Bulbapedia: "Covet inflicts damage and steals the target's held item if it is holding any." The
    /// item is removed from the target and ends up held by the user.
    /// </summary>
    [Test]
    public void OnSecondaryEffect_TargetHoldsItem_UserStealsIt()
    {
        // Arrange
        var item = Substitute.For<IItem>();
        var (script, move, user, target) = CreateTestSetup(item);

        // Act
        script.OnSecondaryEffect(move, target, 0);

        // Assert - the item is taken from the target and given to the user
        target.Received(1).TryStealHeldItem(out Arg.Any<IItem?>());
        user.Received(1).ForceSetHeldItem(item);
    }

    /// <summary>
    /// Bulbapedia: "If the target is not holding an item [...], Covet cannot steal an item."
    /// </summary>
    [Test]
    public void OnSecondaryEffect_TargetHoldsNoItem_NothingIsStolen()
    {
        // Arrange
        var (script, move, user, target) = CreateTestSetup(null);

        // Act
        script.OnSecondaryEffect(move, target, 0);

        // Assert
        target.DidNotReceive().TryStealHeldItem(out Arg.Any<IItem?>());
        user.DidNotReceive().ForceSetHeldItem(Arg.Any<IItem?>());
    }

    /// <summary>
    /// Bulbapedia: "If [...] the user is already holding an item, Covet cannot steal an item."
    /// </summary>
    [Test]
    public void OnSecondaryEffect_UserAlreadyHoldsItem_TargetItemIsNotStolen()
    {
        // Arrange
        var targetItem = Substitute.For<IItem>();
        var (script, move, user, target) = CreateTestSetup(targetItem);
        user.HeldItem.Returns(Substitute.For<IItem>());

        // Act
        script.OnSecondaryEffect(move, target, 0);

        // Assert - the user must not end up with the target's item
        user.DidNotReceive().ForceSetHeldItem(targetItem);
    }
}