using Microsoft.EntityFrameworkCore;

using RolemasterDb.App.Data;
using RolemasterDb.App.Domain;
using RolemasterDb.App.Features;
using RolemasterDb.CriticalParsing;
using AppCriticalEffectCodes = RolemasterDb.App.Domain.CriticalEffectCodes;

namespace RolemasterDb.ImportTool.Tests;

public sealed class CriticalCellReparseIntegrationTests
{
    [Fact]
    public void Shared_cell_parser_extracts_base_effects_and_condition_branches()
    {
        var legend = new AffixLegend(
            new Dictionary<string, string>(StringComparer.Ordinal)
            {
                ["∫"] = AppCriticalEffectCodes.StunnedRounds
            },
            [],
            supportsFoePenalty: false,
            supportsAttackerBonus: false,
            supportsPowerPointModifier: false);

        var content = CriticalCellTextParser.Parse(
            "Strike to thigh.\r\n+10H\r\nWith greaves: glancing blow.\r\n2∫",
            legend);

        Assert.Equal("Strike to thigh.", content.DescriptionText);
        Assert.Equal("+10H", content.RawAffixText);
        Assert.Contains(content.Effects, effect => effect.EffectCode == AppCriticalEffectCodes.DirectHits && effect.ValueInteger == 10);
        Assert.Single(content.Branches);
        Assert.Equal("with_greaves", content.Branches[0].ConditionKey);
        Assert.Equal("glancing blow.", content.Branches[0].DescriptionText);
        Assert.Contains(content.Branches[0].Effects, effect => effect.EffectCode == AppCriticalEffectCodes.StunnedRounds && effect.DurationRounds == 2);
        Assert.Empty(content.ValidationErrors);
    }

    [Fact]
    public async Task Lookup_service_reparse_uses_shared_parser_and_table_legend_data()
    {
        var databasePath = Path.Combine(Path.GetTempPath(), $"rolemaster-reparse-{Guid.NewGuid():N}.db");

        await using (var seedContext = CreateDbContext(databasePath))
        {
            await seedContext.Database.EnsureCreatedAsync();

            var table = new CriticalTable
            {
                Slug = "slash",
                DisplayName = "Slash Critical Strike Table",
                Family = "standard",
                SourceDocument = "Slash.pdf",
                Notes = null
            };
            var column = new CriticalColumn
            {
                CriticalTable = table,
                ColumnKey = "B",
                Label = "B",
                Role = "severity",
                SortOrder = 2
            };
            var rollBand = new CriticalRollBand
            {
                CriticalTable = table,
                Label = "36-40",
                MinRoll = 36,
                MaxRoll = 40,
                SortOrder = 8
            };
            var result = new CriticalResult
            {
                CriticalTable = table,
                CriticalColumn = column,
                CriticalRollBand = rollBand,
                RawCellText = "Old text",
                DescriptionText = "Old description",
                ParseStatus = "verified",
                ParsedJson = "{}"
            };

            result.Effects.Add(new CriticalEffect
            {
                EffectCode = AppCriticalEffectCodes.StunnedRounds,
                Target = "foe",
                DurationRounds = 1,
                IsPermanent = false,
                SourceType = "symbol",
                SourceText = "∫"
            });

            seedContext.CriticalTables.Add(table);
            seedContext.CriticalResults.Add(result);
            await seedContext.SaveChangesAsync();
        }

        var lookupService = new LookupService(CreateDbContextFactory(databasePath));
        await using var verifyContext = CreateDbContext(databasePath);
        var resultId = await verifyContext.CriticalResults
            .Where(item => item.CriticalTable.Slug == "slash")
            .Select(item => item.Id)
            .SingleAsync();

        var response = await lookupService.ReparseCriticalCellAsync(
            "slash",
            resultId,
            "Strike to thigh.\n+10H\nWith greaves: glancing blow.\n2∫");

        Assert.NotNull(response);
        Assert.Equal("Strike to thigh.", response!.DescriptionText);
        Assert.Contains(response.Effects, effect => effect.EffectCode == AppCriticalEffectCodes.DirectHits && effect.ValueInteger == 10);
        Assert.Contains(response.Branches, branch =>
            branch.ConditionKey == "with_greaves" &&
            branch.DescriptionText == "glancing blow." &&
            branch.Effects.Any(effect => effect.EffectCode == AppCriticalEffectCodes.StunnedRounds && effect.DurationRounds == 2));
        Assert.Empty(response.ValidationMessages);
    }

    private static RolemasterDbContext CreateDbContext(string databasePath)
    {
        var options = new DbContextOptionsBuilder<RolemasterDbContext>()
            .UseSqlite($"Data Source={databasePath}")
            .Options;

        return new RolemasterDbContext(options);
    }

    private static IDbContextFactory<RolemasterDbContext> CreateDbContextFactory(string databasePath)
    {
        var options = new DbContextOptionsBuilder<RolemasterDbContext>()
            .UseSqlite($"Data Source={databasePath}")
            .Options;

        return new TestRolemasterDbContextFactory(options);
    }
}
