using SqlSugar;

namespace DBHelper
{
    /// <summary>
    /// DB，禁止跨上下文使用
    /// 1.异步情况： 在同一串await 中是一个上下文 (await 会改变线程和同步是不一样的)
    /// 2.同步情况： 在同一个线程是同一个上下文
    /// </summary>
    public class Db
    {
        /// <summary>
        /// 上下文集合
        /// </summary>
        private static readonly List<ContextList> _contexts = new List<ContextList>();

        /// <summary>
        /// 默认上下文类类型
        /// </summary>
        public static string DefaultDbContextType { get; private set; } = null!;

        /// <summary>
        /// 指定连接连接
        /// </summary>
        /// <typeparam name="T">业务代码</typeparam>
        /// <param name="func">业务逻辑</param>
        /// <param name="key">连接对应的Key</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static T Do<T>(Func<Db, T> func, string key)
        {
            var db = new Db();

            db.Context(key).BeginTran();
            var res = func(db);
            db.Context(key).CommitTran();
            return res;
        }

        /// <summary>
        /// 使用设置好的默认链接
        /// </summary>
        /// <param name="act">执行内容</param>
        public static void Do(Action<Db> act)
        {
            Do(db =>
            {
                act(db);
                return 1;
            }, DefaultDbContextType);
        }

        /// <summary>
        /// 使用指定默认链接
        /// </summary>
        /// <param name="act">执行内容</param>
        /// <param name="key">连接对应的Key</param>
        public static void Do(Action<Db> act, string key)
        {
            Do(db =>
            {
                act(db);
                return 1;
            }, key);
        }

        /// <summary>
        /// 设置默认链接
        /// </summary>
        /// <param name="key"></param>
        public static void SetDefaultDbContextType(string key)
        {
            DefaultDbContextType = key;
        }

        /// <summary>
        /// 默认链接
        /// </summary>
        public SqlSugarScope Default
        {
            get
            {
                if (DefaultDbContextType == null)
                    throw new Exception("请先设置默认数据库,调用静态方法SetDefaultDbContextType()");
                return Context(DefaultDbContextType);
            }
        }

        /// <summary>
        /// 创建一个数据库连接
        /// </summary>
        /// <param name="config">数据库配置信息</param>
        /// <param name="key">数据库Key</param>
        /// <returns></returns>
        public static SqlSugarScope CreateContext(ConnectionConfig config, string key)
        {
            var ctx = _contexts.FirstOrDefault(v => v.Key == key);
            if (ctx != null) return ctx.Client;
            ctx = new ContextList(key, new SqlSugarScope(new ConnectionConfig()
            {
                ConnectionString = config.ConnectionString,
                DbType = config.DbType,
                IsAutoCloseConnection = true
            }), config);

            _contexts.Add(ctx);
            return ctx.Client;
        }

        /// <summary>
        /// 根据Key获取指定数据库连接
        /// </summary>
        /// <param name="key">目标数据库在配置中的Key</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public SqlSugarScope Context(string key)
        {
            var ctx = _contexts.FirstOrDefault(v => v.Key == key);
            if (ctx == null) throw new Exception("没有对应的链接，请先调用创建");
            return ctx.Client;
        }
    }

    /// <summary>
    /// 链接
    /// </summary>
    public class ContextList

    {
        /// <summary>
        ///
        /// </summary>
        /// <param name="key"></param>
        /// <param name="client"></param>
        /// <param name="connectionConfig"></param>
        public ContextList(string key, SqlSugarScope client, ConnectionConfig connectionConfig)
        {
            Key = key;
            Client = client;
            ConnectionConfig = connectionConfig;
        }

        /// <summary>
        ///
        /// </summary>
        public string Key { get; set; }

        /// <summary>
        ///
        /// </summary>
        public SqlSugarScope Client { get; set; }

        /// <summary>
        ///
        /// </summary>
        public ConnectionConfig ConnectionConfig { get; set; }
    }
}
