using RolemasterDb.ImportTool.Parsing;

namespace RolemasterDb.ImportTool.Tests;

public sealed class CriticalImportArtifactGenerationIntegrationTests
{
    private static readonly PdfXmlExtractor Extractor = new();
    private static readonly StandardCriticalTableParser StandardParser = new();

    [Fact]
    public async Task Generated_artifacts_include_page_and_cell_source_images()
    {
        var (parseResult, artifactPaths) = await LoadPreparedSlashParseResultAsync();
        var result = FindResult(parseResult, "71-75", "A");
        var cellArtifact = parseResult.Cells.Single(item =>
            item.GroupKey is null &&
            item.RollBandLabel == "71-75" &&
            item.ColumnKey == "A");

        Assert.True(result.SourceBounds.PageNumber > 0);
        Assert.True(result.SourceBounds.Width > 0);
        Assert.True(result.SourceBounds.Height > 0);
        Assert.NotNull(result.SourceImagePath);
        Assert.NotNull(result.SourceImageCrop);
        Assert.Equal(result.SourceImagePath, cellArtifact.SourceImagePath);
        Assert.NotNull(cellArtifact.SourceImageCrop);
        Assert.True(File.Exists(artifactPaths.GetPageImagePath(result.SourceBounds.PageNumber)));
        Assert.True(File.Exists(artifactPaths.ResolveRelativePath(result.SourceImagePath!)));
    }

    private static async Task<(CriticalTableParseResult ParseResult, ImportArtifactPaths ArtifactPaths)> LoadPreparedSlashParseResultAsync()
    {
        var entry = LoadManifest().Tables.Single(item => item.Slug == "slash");
        var xmlPath = Path.Combine(GetArtifactCacheRoot(), $"{entry.Slug}.xml");

        if (!File.Exists(xmlPath))
        {
            await Extractor.ExtractAsync(Path.Combine(GetRepositoryRoot(), entry.PdfPath), xmlPath);
        }

        var parseResult = StandardParser.Parse(entry, await File.ReadAllTextAsync(xmlPath));
        var artifactRoot = Path.Combine(GetArtifactCacheRoot(), Guid.NewGuid().ToString("N"));
        var artifactPaths = ImportArtifactPaths.Create(artifactRoot, entry.Slug);
        var generator = new CriticalSourceImageArtifactGenerator(new PdfXmlExtractor());

        await generator.GenerateAsync(Path.Combine(GetRepositoryRoot(), entry.PdfPath), artifactPaths, parseResult);
        return (parseResult, artifactPaths);
    }

    private static ParsedCriticalResult FindResult(CriticalTableParseResult parseResult, string rollBandLabel, string columnKey) =>
        parseResult.Table.Results.Single(item =>
            item.GroupKey is null &&
            item.RollBandLabel == rollBandLabel &&
            item.ColumnKey == columnKey);

    private static CriticalImportManifest LoadManifest() =>
        new CriticalImportManifestLoader().Load(Path.Combine(GetRepositoryRoot(), "sources", "critical-import-manifest.json"));

    private static string GetArtifactCacheRoot()
    {
        var cacheRoot = Path.Combine(Path.GetTempPath(), "RolemasterDb.ImportTool.MergeTests");
        Directory.CreateDirectory(cacheRoot);
        return cacheRoot;
    }

    private static string GetRepositoryRoot()
    {
        var probe = new DirectoryInfo(AppContext.BaseDirectory);

        while (probe is not null)
        {
            if (File.Exists(Path.Combine(probe.FullName, "RolemasterDB.slnx")))
            {
                return probe.FullName;
            }

            probe = probe.Parent;
        }

        throw new InvalidOperationException("Could not find the repository root for integration tests.");
    }
}
