using AyCode.Core.Helpers;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore;
using AyCode.Database.DbContexts;
using AyCode.Core.Consts;
using AyCode.Core.Loggers;
using AyCode.Core.Server.Loggers;

namespace AyCode.Database.Extensions;

public static class AcDbTransactionExtension
{
    /// <summary>
    /// BeginTransaction
    /// </summary>
    /// <returns></returns>
    private static IDbContextTransaction OpenTransaction<TDbContext>(this TDbContext ctx) where TDbContext : AcDbContextBase
    {
        ctx.Database.AutoTransactionBehavior = AutoTransactionBehavior.Never;

        return ctx.Database.BeginTransaction(); //IDbContextTransaction
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns>True, ha sikeres volt a Commit.</returns>
    private static bool CommitTransaction<TDbContext>(this TDbContext ctx, bool throwException = false) where TDbContext : AcDbContextBase
    {
        var result = false;
        var transaction = ctx.Database?.CurrentTransaction;

        if (transaction == null) return false;

        try
        {
            ctx.SaveChanges();
            transaction.Commit();

            result = true;
        }
        catch (Exception ex)
        {
            var errorText = $"Transaction({ctx}) transaction ROLLBACK!{AcEnv.NL}";

            transaction.Rollback();

            if (throwException) throw new Exception(errorText, ex);
            GlobalLogger.Error($"{errorText}", ex);
        }
        return result;
    }

    public static Task<bool> TransactionAsync<TDbContext>(this TDbContext ctx, Func<TDbContext, bool> callbackTransactionBody, bool throwException = false) where TDbContext : AcDbContextBase
        => TaskHelper.ToThreadPoolTask(() => ctx.Transaction(callbackTransactionBody, throwException));

    public static bool Transaction<TDbContext>(this TDbContext ctx, Func<TDbContext, bool> callbackTransactionBody, bool throwException = false) where TDbContext : AcDbContextBase
    {
        var result = false;

        try
        {
            using var transaction = ctx.OpenTransaction();

            if (callbackTransactionBody(ctx)) result = ctx.CommitTransaction(throwException);
            else
            {
                transaction.Rollback();
                GlobalLogger.Warning($"Transaction({ctx}) transaction ROLLBACK!");
            }
        }
        catch (Exception ex)
        {
            if (throwException) throw;

            result = false;
            GlobalLogger.Error($"Transaction({ctx}) transaction error...{AcEnv.NL}", ex);
        }
        finally
        {
            //result = ctx.CloseDbContext(false) && result;
        }

        return result;
    }
}