using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using NPin.Framework.SqlSugarCore.Abstractions;
using Volo.Abp.Data;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading;
using Volo.Abp.Uow;

namespace NPin.Framework.SqlSugarCore.Uow;

public class UnitOfWorkSqlSugarDbContextProvider<TDbContext> : ISugarDbContextProvider<TDbContext>
    where TDbContext : ISqlSugarDbContext
{
    private readonly ISqlSugarDbConnectionCreator _dbConnectionCreator;
    private ILogger<UnitOfWorkSqlSugarDbContextProvider<TDbContext>> Logger { get; set; }
    private IServiceProvider ServiceProvider { get; set; }

    private static AsyncLocalDbContextAccessor ContextInstance => AsyncLocalDbContextAccessor.Instance;
    protected readonly IUnitOfWorkManager UnitOfWorkManager;
    protected readonly IConnectionStringResolver ConnectionStringResolver;
    protected readonly ICancellationTokenProvider CancellationTokenProvider;
    protected readonly ICurrentTenant CurrentTenant;

    public UnitOfWorkSqlSugarDbContextProvider(
        IUnitOfWorkManager unitOfWorkManager,
        IConnectionStringResolver connectionStringResolver,
        ICancellationTokenProvider cancellationTokenProvider,
        ICurrentTenant currentTenant,
        ISqlSugarDbConnectionCreator dbConnectionCreator
    )
    {
        UnitOfWorkManager = unitOfWorkManager;
        ConnectionStringResolver = connectionStringResolver;
        CancellationTokenProvider = cancellationTokenProvider;
        CurrentTenant = currentTenant;
        Logger = NullLogger<UnitOfWorkSqlSugarDbContextProvider<TDbContext>>.Instance;
        _dbConnectionCreator = dbConnectionCreator;
    }

    public virtual async Task<TDbContext> GetDbContextAsync()
    {
        var connectionStringName = ConnectionStrings.DefaultConnectionStringName;

        // 获取当前的连接字符串，未开启多租户时为空
        var connectionString = await ResolveConnectionStringAsync(connectionStringName);
        var dbContextKey = $"{GetType().FullName}_{connectionString}";

        var unitOfWork = UnitOfWorkManager.Current;
        if (unitOfWork == null || !unitOfWork.Options.IsTransactional)
        {
            // set if is null
            ContextInstance.Current ??= (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();

            var dbContext = (TDbContext)ContextInstance.Current;
            // 提高体验，取消uow的强制性
            // 若不启用uow，创建新db，不开启事务
            return dbContext;
        }

        // 尝试当前工作单元获取db
        var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
        if (databaseApi == null)
        {
            databaseApi =
                new SqlSugarDatabaseApi(CreateDbContextAsync(unitOfWork, connectionStringName, connectionString)
                    .Result);
            unitOfWork.AddDatabaseApi(dbContextKey, databaseApi);
        }

        return (TDbContext)((SqlSugarDatabaseApi)databaseApi).DbContext;
    }

    /// <summary>
    /// 解析连接字符串
    /// </summary>
    /// <param name="connectionStringName"></param>
    /// <returns></returns>
    protected virtual async Task<string> ResolveConnectionStringAsync(string connectionStringName)
    {
        if (typeof(TDbContext).IsDefined(typeof(IgnoreMultiTenancyAttribute), false))
        {
            using (CurrentTenant.Change(null))
            {
                return await ConnectionStringResolver.ResolveAsync(connectionStringName);
            }
        }

        return await ConnectionStringResolver.ResolveAsync(connectionStringName);
    }

    protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork, string connectionStringName,
        string connectionString)
    {
        var creationContext = new SqlSugarDbContextCreationContext(connectionStringName, connectionString);
        //将连接key进行传值
        using (SqlSugarDbContextCreationContext.Use(creationContext))
        {
            var dbContext = await CreateDbContextAsync(unitOfWork);
            return dbContext;
        }
    }

    protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork)
    {
        return unitOfWork.Options.IsTransactional
            ? await CreateDbContextWithTransactionAsync(unitOfWork)
            : unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
    }

    protected virtual async Task<TDbContext> CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork)
    {
        //事务key
        var transactionApiKey = $"SqlSugarCore_{SqlSugarDbContextCreationContext.Current.ConnectionString}";

        //尝试查找事务
        var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as SqlSugarTransactionApi;

        //该db还没有进行开启事务
        if (activeTransaction == null)
        {
            //获取到db添加事务即可
            var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
            var transaction = new SqlSugarTransactionApi(
                dbContext
            );
            unitOfWork.AddTransactionApi(transactionApiKey, transaction);

            // await dbContext.SqlSugarClient.Ado.BeginTranAsync();
            return dbContext;
        }

        return (TDbContext)activeTransaction.GetDbContext();
    }
}