using System.Linq;
using PkmnLib.Static.Utils;

namespace PkmnLib.Plugin.Gen7.Scripts.Moves;

[Script(ScriptCategory.Move, "conversion_2")]
public class Conversion2 : Script
{
    /// <inheritdoc />
    public override void OnSecondaryEffect(IExecutingMove move, IPokemon target, byte hit)
    {
        var previousTurnChoices = target.BattleData?.Battle.PreviousTurnChoices;
        var nextExecutingChoice = target.BattleData?.Battle.ChoiceQueue?.Peek();
        var lastMoveByTarget = previousTurnChoices?
            // The previous turn choices include the choices of the current turn, so we need to have special handling for
            // the current turn
            .Select((x, index) =>
            {
                // All choices before the current turn are valid
                if (index < previousTurnChoices.Count - 1)
                    return x;
                // If there is no next choice, we're at the end of the list, so we can just return the whole list
                if (nextExecutingChoice == null)
                    return x;
                // Otherwise we determine where the next choice is and return everything before that
                var indexOfNext = x.IndexOf(nextExecutingChoice);
                if (indexOfNext == -1)
                    return x;
                return x.Take(indexOfNext);
            }).SelectMany(x => x)
            // We only want the last move choice by the target
            .OfType<IMoveChoice>().FirstOrDefault(x => x.User == target);
        if (lastMoveByTarget == null)
        {
            move.GetHitData(target, hit).Fail();
            return;
        }

        var typeLibrary = move.User.BattleData!.Battle.Library.StaticLibrary.Types;
        // Get all types against which the last move would be not very effective
        var type = typeLibrary.GetAllEffectivenessFromAttacking(lastMoveByTarget.ChosenMove.MoveData.MoveType)
            .Where(x => x.effectiveness < 1)
            // Shuffle them randomly, but deterministically
            .OrderBy(_ => move.User.BattleData.Battle.Random.GetInt()).ThenBy(x => x.type.Value)
            // And grab the first one
            .Select(x => x.type).FirstOrDefault();
        if (type == null)
        {
            move.GetHitData(target, hit).Fail();
            return;
        }
        move.User.SetTypes([type]);
    }
}