using System.Threading.Channels;
using Microsoft.Extensions.Logging.Abstractions;
using TeamsISO.Engine.Discovery;
using TeamsISO.Engine.Tests.Fakes;

namespace TeamsISO.Engine.Tests.Discovery;

public class NdiDiscoveryServiceTests
{
    [Fact]
    public void PollOnce_AddsNewParticipantSources_AndIgnoresMalformedStrings()
    {
        var interop = new FakeNdiInterop();
        interop.Sources.Add("PC1 (Teams - Jane)");
        interop.Sources.Add("PC1 (Teams)");
        interop.Sources.Add("Just A Camera");
        interop.Sources.Add("BAD (Teams - )");
        var channel = Channel.CreateUnbounded<DiscoveryEvent>();

        var svc = new NdiDiscoveryService(interop, channel.Writer, NullLogger<NdiDiscoveryService>.Instance);

        svc.PollOnce();

        var emitted = DrainChannel(channel.Reader);
        emitted.OfType<DiscoveryEvent.Added>().Select(a => a.Source.FullName)
            .Should().BeEquivalentTo(new[] { "PC1 (Teams - Jane)", "PC1 (Teams)" });
    }

    [Fact]
    public void PollOnce_EmitsRemoved_WhenSourceDisappears()
    {
        var interop = new FakeNdiInterop();
        interop.Sources.Add("PC1 (Teams - Jane)");
        var channel = Channel.CreateUnbounded<DiscoveryEvent>();

        var svc = new NdiDiscoveryService(interop, channel.Writer, NullLogger<NdiDiscoveryService>.Instance);
        svc.PollOnce();
        DrainChannel(channel.Reader);

        interop.Sources.Clear();
        svc.PollOnce();

        var emitted = DrainChannel(channel.Reader);
        emitted.OfType<DiscoveryEvent.Removed>().Select(r => r.Source.FullName)
            .Should().BeEquivalentTo(new[] { "PC1 (Teams - Jane)" });
    }

    [Fact]
    public void PollOnce_NoChange_EmitsNothing()
    {
        var interop = new FakeNdiInterop();
        interop.Sources.Add("PC1 (Teams - Jane)");
        var channel = Channel.CreateUnbounded<DiscoveryEvent>();

        var svc = new NdiDiscoveryService(interop, channel.Writer, NullLogger<NdiDiscoveryService>.Instance);
        svc.PollOnce(); DrainChannel(channel.Reader);

        svc.PollOnce();

        DrainChannel(channel.Reader).Should().BeEmpty();
    }

    private static List<DiscoveryEvent> DrainChannel(ChannelReader<DiscoveryEvent> reader)
    {
        var list = new List<DiscoveryEvent>();
        while (reader.TryRead(out var ev)) list.Add(ev);
        return list;
    }
}
