using Microsoft.Extensions.Logging;
using ZB.MOM.WW.LocalDb.Internal;

namespace ZB.MOM.WW.LocalDb.Replication.Internal;

/// <summary>
/// Shared construction of a <see cref="SyncSession"/> and its dependencies (OplogStore + LwwApplier)
/// from a <see cref="SqliteLocalDb"/> and the bound options. Both the service and client adapters use
/// this so they build an identical session; snapshot hooks are left null (Task 12 fills them in).
/// </summary>
internal static class SyncSessionFactory
{
    /// <summary>
    /// The engine binds to <see cref="SqliteLocalDb"/> internals (NodeId, Clock, replicated-table
    /// digests), so both adapters require the concrete type AddZbLocalDb registers behind ILocalDb.
    /// </summary>
    public static SqliteLocalDb RequireSqlite(ILocalDb db, string consumer) =>
        db as SqliteLocalDb
        ?? throw new InvalidOperationException(
            $"{consumer} requires the ILocalDb registered by AddZbLocalDb (a {nameof(SqliteLocalDb)}); " +
            $"got {db.GetType().FullName}.");

    public static SyncSession Create(
        SqliteLocalDb db, ReplicationOptions options, ILoggerFactory loggerFactory,
        LocalDbMetrics? metrics = null, SyncStatus? status = null)
    {
        var store = new OplogStore(db, options);
        var applier = new LwwApplier(db);
        var logger = loggerFactory.CreateLogger<SyncSession>();
        var session = new SyncSession(db, store, applier, options, logger, utcNow: null, metrics, status);

        var streamer = new SnapshotStreamer(db, store, options, loggerFactory.CreateLogger<SnapshotStreamer>());
        session.SnapshotSender = streamer.SendAsync;
        session.SnapshotApplier = new SnapshotApplier(db, applier, store, loggerFactory.CreateLogger<SnapshotApplier>());
        return session;
    }
}
