using System.Text.Json;
using EnumerableAsyncProcessor.Extensions;
using PkmnLib.Dynamic.Libraries;
using PkmnLib.Dynamic.Models;
using PkmnLib.Plugin.Gen7;
using PkmnLib.Static.Species;
using PkmnLib.Tests.Integration.Models;

namespace PkmnLib.Tests.Integration;

public class IntegrationTestRunner
{
    public static IEnumerable<Func<IntegrationTestModel>> TestCases()
    {
        var files = Directory.GetFiles("../../../../PkmnLib.Tests/Integration/Tests", "*.json");
        var serializerOptions = new JsonSerializerOptions
        {
            PropertyNameCaseInsensitive = true,
            AllowTrailingCommas = true,
            ReadCommentHandling = JsonCommentHandling.Skip,
        };
        foreach (var file in files)
        {
            yield return () =>
            {
                var json = File.ReadAllText(file);
                var o = JsonSerializer.Deserialize<IntegrationTestModel>(json, serializerOptions)!;
                o.FileName = Path.GetFullPath(file);
                return o;
            };
        }
    }

    private static IDynamicLibrary? _libraryWithRandomness;
    private static IDynamicLibrary? _libraryWithoutRandomness;

    [Test, MethodDataSource(nameof(TestCases))]
    public async Task RunIntegrationTest(IntegrationTestModel test)
    {
        IDynamicLibrary library;
        if (test.BattleSetup.HasDamageRandomness)
        {
            library = _libraryWithRandomness ??= DynamicLibraryImpl.Create([
                new Gen7Plugin(new Gen7PluginConfiguration
                {
                    DamageCalculatorHasRandomness = true,
                }),
            ]);
        }
        else
        {
            library = _libraryWithoutRandomness ??= DynamicLibraryImpl.Create([
                new Gen7Plugin(new Gen7PluginConfiguration
                {
                    DamageCalculatorHasRandomness = false,
                }),
            ]);
        }

        await TestContext.Current!.OutputWriter.WriteLineAsync("File: " + $"file://{test.FileName}");
        TestContext.Current.Output.AttachArtifact(new Artifact
        {
            File = new FileInfo(test.FileName),
            DisplayName = test.Name,
        });

        var parties = await test.BattleSetup.Parties.SelectAsync(async Task<IBattleParty> (x) =>
        {
            var party = new PokemonPartyImpl(6);
            for (var index = 0; index < x.Pokemon.Length; index++)
            {
                var pokemon = x.Pokemon[index];
                await Assert.That(library.StaticLibrary.Species.TryGet(pokemon.Species, out var species)).IsTrue();
                var mon = new PokemonImpl(library, species!, species!.GetDefaultForm(), new AbilityIndex
                {
                    IsHidden = false,
                    Index = 0,
                }, pokemon.Level, 0, Gender.Genderless, 0, "hardy");
                foreach (var move in pokemon.Moves)
                {
                    mon.LearnMove(move, MoveLearnMethod.Unknown, 255);
                }

                party.SwapInto(mon, index);
            }

            return new BattlePartyImpl(party, x.Indices.Select(y => new ResponsibleIndex(y[0], y[1])).ToArray());
        }).ProcessOneAtATime().GetResultsAsync();
        using var battle = new BattleImpl(library, parties, test.BattleSetup.CanFlee, test.BattleSetup.NumberOfSides,
            test.BattleSetup.PositionsPerSide, false, test.BattleSetup.EnvironmentName ?? "grass",
            test.BattleSetup.Seed);

        foreach (var action in test.Actions)
        {
            await action.Execute(battle);
        }
    }
}