using Microsoft.Extensions.DependencyInjection;
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;

namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;

/// <summary>
/// Default <see cref="ISchemaLibraryQueryService"/> implementation. Reads the
/// named JSON-Schema library directly from <see cref="ISharedSchemaRepository"/> over a
/// fresh DI scope per query — mirroring <c>AuditLogQueryService</c> /
/// <c>KpiHistoryQueryService</c> so a value form's auto-load never races other reads on
/// the shared circuit-scoped DbContext. Read-only; no mutation goes through here.
/// </summary>
public sealed class SchemaLibraryQueryService : ISchemaLibraryQueryService
{
    private readonly IServiceScopeFactory _scopeFactory;

    /// <summary>
    /// Initializes a new instance of the <see cref="SchemaLibraryQueryService"/>.
    /// </summary>
    /// <param name="scopeFactory">Factory used to open a fresh DI scope (and DbContext) per query.</param>
    public SchemaLibraryQueryService(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory ?? throw new ArgumentNullException(nameof(scopeFactory));
    }

    /// <inheritdoc/>
    public async Task<IReadOnlyDictionary<string, string>> GetSchemaMapAsync(
        CancellationToken cancellationToken = default)
    {
        await using var scope = _scopeFactory.CreateAsyncScope();
        var repo = scope.ServiceProvider.GetRequiredService<ISharedSchemaRepository>();
        var all = await repo.ListAsync(cancellationToken);

        // Ordinal-keyed to match the lib:Name resolver's exact-name lookup. Name is
        // DB-unique, so a list yields at most one row per name and no real collision
        // occurs; the indexer assignment is defensive only — should two rows ever share
        // a name (e.g. a mid-write transient read), the later one in enumeration order
        // overwrites the earlier rather than throwing.
        var map = new Dictionary<string, string>(StringComparer.Ordinal);
        foreach (var schema in all)
        {
            map[schema.Name] = schema.SchemaJson;
        }

        return map;
    }

    /// <inheritdoc/>
    public async Task<string?> ResolveAsync(string name, CancellationToken cancellationToken = default)
    {
        if (string.IsNullOrEmpty(name))
        {
            return null;
        }

        await using var scope = _scopeFactory.CreateAsyncScope();
        var repo = scope.ServiceProvider.GetRequiredService<ISharedSchemaRepository>();
        var schema = await repo.GetByNameAsync(name, cancellationToken);
        return schema?.SchemaJson;
    }
}
