using GmRelay.Shared.Features.Sessions.CreateSession;
using GmRelay.Shared.Platform;

namespace GmRelay.Bot.Tests.Features.Sessions.CreateSession;

public sealed class PlatformNeutralSessionInteractionCommandTests
{
    [Fact]
    public void JoinSessionCommand_ShouldExposePlatformNeutralInteractionContext()
    {
        AssertProperty<JoinSessionCommand>("SessionId", typeof(Guid));
        AssertProperty<JoinSessionCommand>("User", typeof(PlatformUser));
        AssertProperty<JoinSessionCommand>("InteractionId", typeof(string));
        AssertProperty<JoinSessionCommand>("Group", typeof(PlatformGroup));
        AssertProperty<JoinSessionCommand>("ScheduleMessage", typeof(PlatformMessageRef));
        AssertProperty<JoinSessionCommand>("DeferScheduleUpdate", typeof(bool));
        AssertNoTelegramSpecificProperties<JoinSessionCommand>();
    }

    [Fact]
    public void LeaveSessionCommand_ShouldExposePlatformNeutralInteractionContext()
    {
        AssertProperty<LeaveSessionCommand>("SessionId", typeof(Guid));
        AssertProperty<LeaveSessionCommand>("User", typeof(PlatformUser));
        AssertProperty<LeaveSessionCommand>("InteractionId", typeof(string));
        AssertProperty<LeaveSessionCommand>("Group", typeof(PlatformGroup));
        AssertProperty<LeaveSessionCommand>("ScheduleMessage", typeof(PlatformMessageRef));
        AssertProperty<LeaveSessionCommand>("DeferScheduleUpdate", typeof(bool));
        AssertNoTelegramSpecificProperties<LeaveSessionCommand>();
    }

    [Fact]
    public void SessionInteractionResult_ShouldExposeReplyTextAndUpdatedView()
    {
        var resultType = typeof(JoinSessionCommand).Assembly.GetType(
            "GmRelay.Shared.Features.Sessions.CreateSession.SessionInteractionResult");

        Assert.NotNull(resultType);
        AssertProperty(resultType, "ReplyText", typeof(string));
        AssertProperty(resultType, "UpdatedView", typeof(GmRelay.Shared.Rendering.SessionBatchViewModel));
    }

    private static void AssertProperty<T>(string name, Type expectedType)
    {
        AssertProperty(typeof(T), name, expectedType);
    }

    private static void AssertProperty(Type type, string name, Type expectedType)
    {
        var property = Assert.Single(type.GetProperties(), property => property.Name == name);

        Assert.Equal(expectedType, property.PropertyType);
    }

    private static void AssertNoTelegramSpecificProperties<T>()
    {
        var names = typeof(T).GetProperties().Select(property => property.Name).ToArray();

        Assert.DoesNotContain(names, name => name.Contains("Telegram", StringComparison.Ordinal));
        Assert.DoesNotContain("ChatId", names);
        Assert.DoesNotContain("MessageId", names);
        Assert.DoesNotContain("TelegramUserId", names);
        Assert.DoesNotContain("TelegramUsername", names);
    }
}
