using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Configuration.Enums;

namespace ZB.MOM.WW.OtOpcUa.Core.Authorization;

/// <summary>
///     Tri-state result of an <see cref="IPermissionEvaluator.Authorize"/> call.
///     Phase 6.2 only produces <see cref="AuthorizationVerdict.Allow"/> and
///     <see cref="AuthorizationVerdict.NotGranted"/>; the <see cref="AuthorizationVerdict.Denied"/>
///     variant exists in the model so v2.1 Explicit Deny lands without an API break. Provenance
///     carries the matched grants (or empty when not granted) for audit + the Admin UI "Probe
///     this permission" diagnostic.
/// </summary>
public sealed record AuthorizationDecision(
    AuthorizationVerdict Verdict,
    IReadOnlyList<MatchedGrant> Provenance)
{
    /// <summary>Gets a value indicating whether the authorization decision allows the operation.</summary>
    public bool IsAllowed => Verdict == AuthorizationVerdict.Allow;

    /// <summary>Convenience constructor for the common "no grants matched" outcome.</summary>
    /// <returns>An authorization decision with the <see cref="AuthorizationVerdict.NotGranted"/> verdict.</returns>
    public static AuthorizationDecision NotGranted() => new(AuthorizationVerdict.NotGranted, []);

    /// <summary>Allow with the list of grants that matched.</summary>
    /// <param name="provenance">The list of grants that matched to allow the operation.</param>
    /// <returns>An authorization decision with Allow verdict.</returns>
    public static AuthorizationDecision Allowed(IReadOnlyList<MatchedGrant> provenance)
        => new(AuthorizationVerdict.Allow, provenance);
}

/// <summary>Three-valued authorization outcome.</summary>
public enum AuthorizationVerdict
{
    /// <summary>At least one grant matches the requested (operation, scope) pair.</summary>
    Allow,

    /// <summary>No grant matches. Phase 6.2 default — treated as deny at the OPC UA surface.</summary>
    NotGranted,

    /// <summary>Explicit deny grant matched. Reserved for v2.1; never produced by Phase 6.2.</summary>
    Denied,
}

/// <summary>One grant that contributed to an Allow verdict — for audit / UI diagnostics.</summary>
/// <param name="LdapGroup">LDAP group the matched grant belongs to.</param>
/// <param name="Scope">Where in the hierarchy the grant was anchored.</param>
/// <param name="PermissionFlags">The bitmask the grant contributed.</param>
public sealed record MatchedGrant(
    string LdapGroup,
    NodeAclScopeKind Scope,
    NodePermissions PermissionFlags);
