using ZB.MOM.WW.OtOpcUa.Configuration.Entities;
using ZB.MOM.WW.OtOpcUa.Configuration.Enums;

namespace ZB.MOM.WW.OtOpcUa.Configuration.Services;

/// <summary>
///     CRUD surface for <see cref="LdapGroupRoleMapping"/> — the control-plane mapping from
///     LDAP groups to Admin UI roles. Consumed only by Admin UI code paths; the OPC UA
///     data-path evaluator MUST NOT depend on this interface (see the
///     Phase 6.2 compliance check on control/data-plane separation).
/// </summary>
/// <remarks>
///     <para>
///         This service has no local-cache fallback: a DB outage during sign-in denies logins.
///     </para>
///     <para>
///         The Phase 6.1 <c>ResilientConfigReader</c> pipeline (timeout → retry →
///         fallback-to-sealed-snapshot) this was once expected to run behind was never wired to
///         anything and was deleted along with the rest of the dormant LiteDB local cache, which
///         <c>ZB.MOM.WW.LocalDb</c> supersedes. LocalDb caches the deployed-configuration artifact
///         for driver-role nodes; it does not currently cover admin-plane reads like this one.
///         Reviving the fallback means adding an admin-side cache on LocalDb, not restoring the
///         old pipeline.
///     </para>
/// </remarks>
public interface ILdapGroupRoleMappingService
{
    /// <summary>List every mapping whose LDAP group matches one of <paramref name="ldapGroups"/>.</summary>
    /// <remarks>
    ///     Hot path — fires on every sign-in. The default EF implementation relies on the
    ///     <c>IX_LdapGroupRoleMapping_Group</c> index. The match is a SQL <c>IN (…)</c> whose
    ///     case-sensitivity is determined by the <c>LdapGroup</c> column collation. Case-insensitive
    ///     behaviour requires a case-insensitive (CI) server or column collation — this is a
    ///     deployment requirement. On a case-sensitive-collation server the lookup will silently
    ///     miss rows that differ only in case.
    /// </remarks>
    /// <param name="ldapGroups">The LDAP groups to search for.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>The mappings whose LDAP group matches one of <paramref name="ldapGroups"/>.</returns>
    Task<IReadOnlyList<LdapGroupRoleMapping>> GetByGroupsAsync(
        IEnumerable<string> ldapGroups, CancellationToken cancellationToken);

    /// <summary>Enumerate every mapping; Admin UI listing only.</summary>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>Every LDAP group role mapping.</returns>
    Task<IReadOnlyList<LdapGroupRoleMapping>> ListAllAsync(CancellationToken cancellationToken);

    /// <summary>Create a new grant.</summary>
    /// <exception cref="InvalidLdapGroupRoleMappingException">
    ///     Thrown when the proposed row violates an invariant (IsSystemWide inconsistent with
    ///     ClusterId, duplicate (group, cluster) pair, etc.) — ValidatedLdapGroupRoleMappingService
    ///     is the write surface that enforces these; the raw service here surfaces DB-level violations.
    /// </exception>
    /// <param name="row">The LDAP group role mapping to create.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>The created mapping row.</returns>
    Task<LdapGroupRoleMapping> CreateAsync(LdapGroupRoleMapping row, CancellationToken cancellationToken);

    /// <summary>Delete a mapping by its surrogate key.</summary>
    /// <param name="id">The unique identifier of the mapping to delete.</param>
    /// <param name="cancellationToken">The cancellation token.</param>
    /// <returns>A task that represents the asynchronous operation.</returns>
    Task DeleteAsync(Guid id, CancellationToken cancellationToken);
}

/// <summary>Thrown when <see cref="LdapGroupRoleMapping"/> authoring violates an invariant.</summary>
public sealed class InvalidLdapGroupRoleMappingException : Exception
{
    /// <summary>Initializes a new instance of the InvalidLdapGroupRoleMappingException.</summary>
    /// <param name="message">The error message.</param>
    public InvalidLdapGroupRoleMappingException(string message) : base(message) { }
}
