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

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

public sealed class NodeAclService(OtOpcUaConfigDbContext db, AclChangeNotifier? notifier = null)
{
    public Task<List<NodeAcl>> ListAsync(long generationId, CancellationToken ct) =>
        db.NodeAcls.AsNoTracking()
            .Where(a => a.GenerationId == generationId)
            .OrderBy(a => a.LdapGroup)
            .ThenBy(a => a.ScopeKind)
            .ToListAsync(ct);

    public async Task<NodeAcl> GrantAsync(
        long draftId, string clusterId, string ldapGroup, NodeAclScopeKind scopeKind, string? scopeId,
        NodePermissions permissions, string? notes, CancellationToken ct)
    {
        var acl = new NodeAcl
        {
            GenerationId = draftId,
            NodeAclId = $"acl-{Guid.NewGuid():N}"[..20],
            ClusterId = clusterId,
            LdapGroup = ldapGroup,
            ScopeKind = scopeKind,
            ScopeId = scopeId,
            PermissionFlags = permissions,
            Notes = notes,
        };
        db.NodeAcls.Add(acl);
        await db.SaveChangesAsync(ct);

        if (notifier is not null)
            await notifier.NotifyNodeAclChangedAsync(clusterId, draftId, ct);

        return acl;
    }

    public async Task RevokeAsync(Guid nodeAclRowId, CancellationToken ct)
    {
        var row = await db.NodeAcls.FirstOrDefaultAsync(a => a.NodeAclRowId == nodeAclRowId, ct);
        if (row is null) return;
        db.NodeAcls.Remove(row);
        await db.SaveChangesAsync(ct);

        if (notifier is not null)
            await notifier.NotifyNodeAclChangedAsync(row.ClusterId, row.GenerationId, ct);
    }
}
