using Microsoft.EntityFrameworkCore;
using ZB.MOM.WW.OtOpcUa.Configuration;
using ZB.MOM.WW.OtOpcUa.Configuration.Validation;

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

/// <summary>
///     Runs the managed <see cref="DraftValidator"/> against a draft's snapshot loaded from the
///     Configuration DB. Used by the draft editor's inline validation panel and by the publish
///     dialog's pre-check. Structural-only SQL checks live in <c>sp_ValidateDraft</c>; this layer
///     owns the content / cross-generation / regex rules.
/// </summary>
public sealed class DraftValidationService(OtOpcUaConfigDbContext db)
{
    public async Task<IReadOnlyList<ValidationError>> ValidateAsync(long draftId, CancellationToken ct)
    {
        var draft = await db.ConfigGenerations.AsNoTracking()
            .FirstOrDefaultAsync(g => g.GenerationId == draftId, ct)
            ?? throw new InvalidOperationException($"Draft {draftId} not found");

        var snapshot = new DraftSnapshot
        {
            GenerationId = draft.GenerationId,
            ClusterId = draft.ClusterId,
            Namespaces = await db.Namespaces.AsNoTracking().Where(n => n.GenerationId == draftId).ToListAsync(ct),
            DriverInstances = await db.DriverInstances.AsNoTracking().Where(d => d.GenerationId == draftId).ToListAsync(ct),
            Devices = await db.Devices.AsNoTracking().Where(d => d.GenerationId == draftId).ToListAsync(ct),
            UnsAreas = await db.UnsAreas.AsNoTracking().Where(a => a.GenerationId == draftId).ToListAsync(ct),
            UnsLines = await db.UnsLines.AsNoTracking().Where(l => l.GenerationId == draftId).ToListAsync(ct),
            Equipment = await db.Equipment.AsNoTracking().Where(e => e.GenerationId == draftId).ToListAsync(ct),
            Tags = await db.Tags.AsNoTracking().Where(t => t.GenerationId == draftId).ToListAsync(ct),
            PollGroups = await db.PollGroups.AsNoTracking().Where(p => p.GenerationId == draftId).ToListAsync(ct),

            PriorEquipment = await db.Equipment.AsNoTracking()
                .Where(e => e.GenerationId != draftId
                         && db.ConfigGenerations.Any(g => g.GenerationId == e.GenerationId && g.ClusterId == draft.ClusterId))
                .ToListAsync(ct),
            ActiveReservations = await db.ExternalIdReservations.AsNoTracking()
                .Where(r => r.ReleasedAt == null)
                .ToListAsync(ct),
        };

        return DraftValidator.Validate(snapshot);
    }
}
