using DodoSSH.Contracts;

namespace DodoSSH.Client.Sync.Tests;

/// <summary>
/// The registry of synchronised item types, and the one property that has to hold about it.
/// </summary>
/// <remarks>
/// Adding an item type touches a cipher, a codec, a merge, a repository and a view. The failure this pins is
/// the one that none of those would reveal: a type that can be created, encrypted, merged and listed
/// perfectly, and is never asked for in a pull — so it works on the machine that made it and exists nowhere
/// else. Deriving the filter from the registry is what prevents it; these tests are what notice if the
/// derivation stops holding.
/// </remarks>
public sealed class ItemKindsTests
{
    [Fact]
    public void ThePullFilterNamesEveryTypeThisBuildSynchronises()
    {
        ItemKinds.SyncedTypes.ShouldBe(
        [
            SyncEntityType.Host,
            SyncEntityType.SshKey,
            SyncEntityType.Credential,
            SyncEntityType.KnownHostKey,
            SyncEntityType.HostGroup,
            SyncEntityType.Tag,
            SyncEntityType.Snippet,
            SyncEntityType.ConnectionLogEntry,
            SyncEntityType.ActivityLogEntry,
            SyncEntityType.ObjectStore,
        ]);
    }

    [Fact]
    public void ThePullFilterIsNotEmpty()
    {
        // Stated separately from the list above because the consequence of an empty one is quiet rather
        // than loud: the contract says an empty filter means every type, so the client would ask the server
        // for everything it holds and then discard most of the answer in ApplyAsync. The way it could
        // actually become empty is a static initialisation order slip — SyncedTypes projects Registry, and a
        // reordering of the two declarations would leave it reading an unassigned array.
        ItemKinds.SyncedTypes.ShouldNotBeEmpty();
    }

    [Fact]
    public async Task EveryTypeInThePullFilter_HasAReconciler()
    {
        using var harness = await SyncHarness.CreateAsync();

        var reconcilers = ItemKinds.Reconcilers(
            harness.First.Outbox, harness.First.Conflicts, harness.First.Keyring);

        reconcilers.Keys.Order().ShouldBe(ItemKinds.SyncedTypes.Order());
    }
}
