namespace DodoSSH.Client.Domain.Tests;

/// <summary>
/// Builds hosts, and the groups they are filed under, so each test varies only what it is about.
/// </summary>
internal static class HostFactory
{
    internal static Guid Bastion { get; } = Guid.Parse("0192f0c8-1111-7c3d-8e4f-5a6b7c8d9e01");

    internal static Guid Relay { get; } = Guid.Parse("0192f0c8-2222-7c3d-8e4f-5a6b7c8d9e02");

    /// <summary>A vault SSH key id, for the hosts that bind one.</summary>
    internal static Guid DeployKey { get; } = Guid.Parse("0192f0c8-3333-7c3d-8e4f-5a6b7c8d9e03");

    /// <summary>A group id, for the hosts that are filed under one.</summary>
    internal static Guid Production { get; } = Guid.Parse("0192f0c8-4444-7c3d-8e4f-5a6b7c8d9e04");

    /// <summary>A tag id, for the hosts that wear one.</summary>
    internal static Guid Pci { get; } = Guid.Parse("0192f0c8-8888-7c3d-8e4f-5a6b7c8d9e08");

    /// <summary>A second tag id, for the tests about two people tagging one host.</summary>
    internal static Guid EuWest { get; } = Guid.Parse("0192f0c8-9999-7c3d-8e4f-5a6b7c8d9e09");

    /// <remarks>
    /// <paramref name="port"/> defaults to an explicit 22 rather than to null, so a test that says nothing
    /// about ports gets the host shape that existed before inheritance did — which is what nearly every
    /// suite here is still about. Passing <see langword="null"/> is how a test asks for the new one.
    /// </remarks>
    internal static HostSecret Host(
        string label = "prod-db",
        string hostname = "db.internal",
        int? port = 22,
        string? username = "deploy",
        string? notes = null,
        Guid[]? jumps = null,
        (string Name, string Value)[]? options = null,
        bool relayEnabled = false,
        Guid? sshKeyId = null,
        Guid? credentialId = null,
        bool? asksForPassword = null,
        Guid? groupId = null,
        Guid[]? tags = null,
        string[]? pinnedPaths = null) =>
        new()
        {
            Label = label,
            Hostname = hostname,
            Port = port,
            Username = username,
            Notes = notes,
            JumpHostIds = jumps is null ? JumpChain.Empty : JumpChain.Create(jumps),
            Options = options is null
                ? HostOptions.Empty
                : HostOptions.Create(options.Select(o => new HostOption(o.Name, o.Value))),
            RelayEnabled = relayEnabled,
            SshKeyId = sshKeyId,
            CredentialId = credentialId,
            AsksForPassword = asksForPassword,
            GroupId = groupId,
            TagIds = tags is null ? TagSet.Empty : TagSet.Create(tags),
            PinnedPaths = pinnedPaths is null ? PinnedPathList.Empty : PinnedPathList.Create(pinnedPaths),
        };

    /// <summary>
    /// A group, flat and defaulting nothing unless the test says otherwise.
    /// </summary>
    /// <remarks>
    /// The defaults of this builder are the shape a group had before it could nest or default anything,
    /// which is what most suites still want: a heading with a name. A test that passes nothing here is
    /// asserting about the old shape on purpose.
    /// </remarks>
    internal static HostGroupSecret Group(
        string label = "production",
        Guid? parentId = null,
        int? defaultPort = null,
        string? defaultUsername = null,
        Guid? defaultSshKeyId = null,
        Guid? defaultCredentialId = null) =>
        new()
        {
            Label = label,
            ParentId = parentId,
            DefaultPort = defaultPort,
            DefaultUsername = defaultUsername,
            DefaultSshKeyId = defaultSshKeyId,
            DefaultCredentialId = defaultCredentialId,
        };
}
