namespace ZB.MOM.WW.Auth.Ldap.Internal;

using System.Net.Security;
using ZB.MOM.WW.Auth.Abstractions.Ldap;

/// <summary>
/// A single LDAP search result entry: its DN and a flat attribute bag.
/// </summary>
internal sealed record LdapSearchEntry(
    string Dn,
    IReadOnlyDictionary<string, IReadOnlyList<string>> Attributes);

/// <summary>
/// Abstraction over a single LDAP connection. Allows unit-testing
/// <c>LdapAuthService</c> without a live directory server.
/// </summary>
internal interface ILdapConnection : IDisposable
{
    /// <summary>
    /// Opens (and optionally upgrades to TLS) a connection to the given host.
    /// </summary>
    /// <param name="host">The LDAP server hostname or IP.</param>
    /// <param name="port">The LDAP server port.</param>
    /// <param name="transport">The transport security mode.</param>
    /// <param name="allowInsecure">
    /// When <see langword="true"/> AND no <paramref name="serverCertificateValidationCallback"/> is
    /// supplied, TLS server-certificate validation is bypassed (dev/test only). Ignored when a
    /// validation callback is supplied (the callback wins) or for plaintext transport.
    /// </param>
    /// <param name="timeoutMs">The connection/operation timeout in milliseconds.</param>
    /// <param name="serverCertificateValidationCallback">
    /// Optional TLS server-certificate validation callback. When <see langword="null"/>, the OS trust
    /// store is used (the client does not blind-accept).
    /// </param>
    void Connect(
        string host,
        int port,
        LdapTransport transport,
        bool allowInsecure,
        int timeoutMs,
        RemoteCertificateValidationCallback? serverCertificateValidationCallback);

    /// <summary>Binds with the supplied DN and password. Throws <c>LdapException</c> on bad credentials.</summary>
    void Bind(string dn, string password);

    /// <summary>Executes a subtree search and returns all matching entries.</summary>
    IReadOnlyList<LdapSearchEntry> Search(string searchBase, string filter, IReadOnlyList<string> attributes);
}

/// <summary>Factory that produces <see cref="ILdapConnection"/> instances.</summary>
internal interface ILdapConnectionFactory
{
    ILdapConnection Create();
}
