using System.Reflection;
using Microsoft.Extensions.Options;
using NPin.Framework.SqlSugarCore.Abstractions;
using SqlSugar;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;

namespace NPin.Framework.SqlSugarCore;

public class SqlSugarDbConnectionCreator : ISqlSugarDbConnectionCreator, ITransientDependency
{
    [DisablePropertyInjection] public Action<ISqlSugarClient> OnSqlSugarClientConfig { get; set; }

    [DisablePropertyInjection] public Action<object, DataAfterModel> DataExecuted { get; set; }

    [DisablePropertyInjection] public Action<object, DataFilterModel> DataExecuting { get; set; }

    [DisablePropertyInjection] public Action<string, SugarParameter[]> OnLogExecuting { get; set; }

    [DisablePropertyInjection] public Action<string, SugarParameter[]> OnLogExecuted { get; set; }

    [DisablePropertyInjection] public Action<PropertyInfo, EntityColumnInfo> EntityService { get; set; }
    
    [DisablePropertyInjection] public Action<Type, EntityInfo> EntityNameService { get; set; }

    public DbConnOptions Options { get; }

    public SqlSugarDbConnectionCreator(IOptions<DbConnOptions> options)
    {
        Options = options.Value;
    }

    public void SetDbAop(ISqlSugarClient currentDb)
    {
        currentDb.Aop.OnLogExecuting = this.OnLogExecuting;
        currentDb.Aop.OnLogExecuted = this.OnLogExecuted;
        currentDb.Aop.DataExecuting = this.DataExecuting;
        currentDb.Aop.DataExecuted = this.DataExecuted;
        OnSqlSugarClientConfig(currentDb);
    }

    public ConnectionConfig Build(Action<ConnectionConfig>? action = null)
    {
        var dbConnOptions = Options;

        #region 组装Options

        if (dbConnOptions.DbType is null)
        {
            throw new ArgumentException("DbType配置为空");
        }

        // 读写分离 slave模式
        var slaveConfigs = new List<SlaveConnectionConfig>();
        if (dbConnOptions.EnabledReadWrite)
        {
            if (dbConnOptions.ReadUrl is null)
            {
                throw new ArgumentException("读写分离开启，但读库配置为空");
            }

            var readConn = dbConnOptions.ReadUrl;
            readConn.ForEach(s =>
            {
                // 如果是动态分库，连接串不能写死，需要动态添加，所以此处只配置共享库的连接
                slaveConfigs.Add(new SlaveConnectionConfig { ConnectionString = s });
            });
        }

        #endregion

        #region 组装连接配置

        var connectionConfig = new ConnectionConfig
        {
            ConfigId = ConnectionStrings.DefaultConnectionStringName,
            DbType = dbConnOptions.DbType ?? DbType.Sqlite,
            ConnectionString = dbConnOptions.Url,
            IsAutoCloseConnection = true,
            SlaveConnectionConfigs = slaveConfigs,
            // CodeFirst 非空值判断
            ConfigureExternalServices = new ConfigureExternalServices
            {
                EntityService = (c, p) =>
                {
                    if (new NullabilityInfoContext().Create(c).WriteState is NullabilityState.Nullable)
                    {
                        p.IsNullable = true;
                    }

                    EntityService(c, p);
                },
                EntityNameService = (t, e) =>
                {
                    EntityNameService(t, e);
                }
            },
            // Aop
            AopEvents = new AopEvents
            {
                DataExecuted = DataExecuted,
                DataExecuting = DataExecuting,
                OnLogExecuted = OnLogExecuted,
                OnLogExecuting = OnLogExecuting
            }
        };

        if (action is not null)
        {
            action.Invoke(connectionConfig);
        }

        #endregion

        return connectionConfig;
    }
}