using PkmnLib.Dynamic.Libraries;
using PkmnLib.Dynamic.ScriptHandling;
using PkmnLib.Static.Species;

namespace PkmnLib.Plugin.Gen7.Tests.DataTests;

public class AbilityDataTests
{
    public record TestCaseData(IDynamicLibrary Library, IAbility Ability)
    {
        /// <inheritdoc />
        public override string ToString() => Ability.Name + " has valid scripts";
    }

    public static IEnumerable<Func<TestCaseData>> AllAbilitiesHaveValidScriptsData()
    {
        var library = LibraryHelpers.LoadLibrary();
        var abilityLibrary = library.StaticLibrary.Abilities;
        foreach (var ability in abilityLibrary)
        {
            if (ability.Effect is null)
                continue;
            yield return () => new TestCaseData(library, ability);
        }
    }

    [Test, MethodDataSource(nameof(AllAbilitiesHaveValidScriptsData))]
    public async Task AllAbilitiesEffectsHaveValidScripts(TestCaseData test)
    {
        var scriptName = test.Ability.Effect;
        if (scriptName is null)
            return;

        try
        {
            await Assert.That(test.Library.ScriptResolver.TryResolve(ScriptCategory.Ability, scriptName.Value,
                test.Ability.Parameters, out _)).IsTrue();
        }
        catch (Exception e)
        {
            // Helper method to find the line number of the effect in the JSON file
            var file = Path.GetFullPath("../../../../Plugins/PkmnLib.Plugin.Gen7/Data/Abilities.jsonc");
            var json = await File.ReadAllLinesAsync(file);
            var moveLineNumber = json.Select((line, index) => new { line, index })
                .FirstOrDefault(x => x.line.Contains($"\"name\": \"{test.Ability.Effect}\""))?.index + 1;
            var effectLineNumber = moveLineNumber + json.Skip(moveLineNumber ?? 0)
                    .Select((line, index) => new { line, index }).FirstOrDefault(x => x.line.Contains("effect"))
                    ?.index +
                1 ?? 0;

            await TestContext.Current!.OutputWriter.WriteLineAsync("File: " + $"file://{file}:{effectLineNumber}");
            throw new AggregateException($"Failed to resolve script for move {test.Ability} with effect {scriptName}",
                e);
        }
    }
}