using Microsoft.Extensions.Logging;
using SqlSugar;
using System.Collections.Concurrent;
using System.Reflection;
using Tiobon.Core.Common.Extensions;

namespace Tiobon.Core.Repository.UnitOfWorks;

public class UnitOfWorkManage : IUnitOfWorkManage
{
    private readonly ILogger<UnitOfWorkManage> _logger;
    private readonly ISqlSugarClient _sqlSugarClient;

    private int _tranCount { get; set; }
    public int TranCount => _tranCount;
    public readonly ConcurrentStack<string> TranStack = new();

    public UnitOfWorkManage(ISqlSugarClient sqlSugarClient, ILogger<UnitOfWorkManage> logger)
    {
        _sqlSugarClient = sqlSugarClient;
        _logger = logger;
        _tranCount = 0;
    }

    /// <summary>
    /// 获取DB，保证唯一性
    /// </summary>
    /// <returns></returns>
    public SqlSugarScope GetDbClient()
    {
        // 必须要as，后边会用到切换数据库操作
        return _sqlSugarClient as SqlSugarScope;
    }


    public UnitOfWork CreateUnitOfWork()
    {
        UnitOfWork uow = new UnitOfWork();
        uow.Logger = _logger;
        uow.Db = _sqlSugarClient;
        uow.Tenant = (ITenant) _sqlSugarClient;
        uow.IsTran = true;

        uow.Db.Open();
        uow.Tenant.BeginTran();
        _logger.LogDebug("UnitOfWork Begin");
        return uow;
    }

    public void BeginTran()
    {
        lock (this)
        {
            _tranCount++;
            GetDbClient().BeginTran();
        }
    }

    public void BeginTran(MethodInfo method)
    {
        lock (this)
        {
            GetDbClient().BeginTran();
            TranStack.Push(method.GetFullName());
            _tranCount = TranStack.Count;
        }
    }

    public void CommitTran()
    {
        lock (this)
        {
            _tranCount--;
            if (_tranCount == 0)
            {
                try
                {
                    GetDbClient().CommitTran();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    GetDbClient().RollbackTran();
                }
            }
        }
    }

    public void CommitTran(MethodInfo method)
    {
        lock (this)
        {
            string result = "";
            while (!TranStack.IsEmpty && !TranStack.TryPeek(out result))
            {
                Thread.Sleep(1);
            }


            if (result == method.GetFullName())
            {
                try
                {
                    GetDbClient().CommitTran();

                    _logger.LogDebug($"Commit Transaction");
                    Console.WriteLine($"Commit Transaction");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    GetDbClient().RollbackTran();
                    _logger.LogDebug($"Commit Error , Rollback Transaction");
                }
                finally
                {
                    while (!TranStack.TryPop(out _))
                    {
                        Thread.Sleep(1);
                    }

                    _tranCount = TranStack.Count;
                }
            }
        }
    }

    public void RollbackTran()
    {
        lock (this)
        {
            _tranCount--;
            GetDbClient().RollbackTran();
        }
    }

    public void RollbackTran(MethodInfo method)
    {
        lock (this)
        {
            string result = "";
            while (!TranStack.IsEmpty && !TranStack.TryPeek(out result))
            {
                Thread.Sleep(1);
            }

            if (result == method.GetFullName())
            {
                GetDbClient().RollbackTran();
                _logger.LogDebug($"Rollback Transaction");
                Console.WriteLine($"Rollback Transaction");
                while (!TranStack.TryPop(out _))
                {
                    Thread.Sleep(1);
                }

                _tranCount = TranStack.Count;
            }
        }
    }
}