using System.Reflection;
using GmRelay.Shared.Domain;

namespace GmRelay.Bot.Tests.Domain;

public sealed class SessionStatusTests
{
    [Fact]
    public void All_ShouldContainOnlyCanonicalSessionStatuses()
    {
        var allProperty = typeof(SessionStatus).GetProperty(
            "All",
            BindingFlags.Public | BindingFlags.Static);

        Assert.NotNull(allProperty);

        var allStatusValues = Assert.IsAssignableFrom<IReadOnlySet<string>>(allProperty.GetValue(null));
        var expectedStatusValues = new[]
            {
                SessionStatus.Planned,
                SessionStatus.ConfirmationSent,
                SessionStatus.Confirmed,
                SessionStatus.Cancelled
            }
            .Order(StringComparer.Ordinal);

        Assert.Equal(expectedStatusValues, allStatusValues.Order(StringComparer.Ordinal));
    }

    [Fact]
    public void ProductionSources_ShouldNotReferenceLegacySessionStatuses()
    {
        var repositoryRoot = FindRepositoryRoot();
        var productionFiles = Directory.EnumerateFiles(repositoryRoot, "*.*", SearchOption.AllDirectories)
            .Where(path => IsProductionSource(path))
            .ToList();

        var legacyStatuses = new[] { "Recruit" + "ing", "Recruitment" + "Closed" };
        var offenders = productionFiles
            .SelectMany(path => legacyStatuses
                .Where(status => File.ReadAllText(path).Contains(status, StringComparison.Ordinal))
                .Select(status => $"{Path.GetRelativePath(repositoryRoot, path)} contains {status}"))
            .ToList();

        Assert.Empty(offenders);
    }

    private static bool IsProductionSource(string path)
    {
        var extension = Path.GetExtension(path);
        var separator = Path.DirectorySeparatorChar;

        return path.Contains($"{separator}src{separator}", StringComparison.Ordinal)
            && !path.Contains($"{separator}bin{separator}", StringComparison.Ordinal)
            && !path.Contains($"{separator}obj{separator}", StringComparison.Ordinal)
            && extension is ".cs" or ".razor" or ".sql";
    }

    private static string FindRepositoryRoot()
    {
        var current = new DirectoryInfo(AppContext.BaseDirectory);

        while (current is not null)
        {
            if (File.Exists(Path.Combine(current.FullName, "GM-Relay.slnx")))
            {
                return current.FullName;
            }

            current = current.Parent;
        }

        throw new InvalidOperationException("Could not find repository root.");
    }
}
