using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Storage;

namespace NetinaShop.Repository.Repositories.Base;
public class RepositoryWrapper : IRepositoryWrapper
{
    private readonly ApplicationContext _context;
    private readonly ICurrentUserService _currentUserService;
    private IDbContextTransaction? _currentTransaction;
    public RepositoryWrapper(ApplicationContext context, ICurrentUserService currentUserService)
    {
        _context = context;
        _currentUserService = currentUserService;
    }

    public IBaseRepository<T> SetRepository<T>() where T : ApiEntity => new BaseRepository<T>(_context, _currentUserService);


    public async Task RollBackAsync(CancellationToken cancellationToken)
    {
        if (_currentTransaction == null)
            throw new ArgumentNullException(nameof(_currentTransaction));
        await _currentTransaction.RollbackAsync(cancellationToken);
    }
    public async Task CommitAsync(CancellationToken cancellationToken)
    {
        if (_currentTransaction == null)
            throw new ArgumentNullException(nameof(_currentTransaction));
        await _currentTransaction.CommitAsync(cancellationToken);
    }
    public async Task BeginTransaction(CancellationToken cancellationToken)
    {
        _currentTransaction = await _context.Database.BeginTransactionAsync(cancellationToken);
    }
    public async Task SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        SetAuditables();
        await _context.SaveChangesAsync(cancellationToken);
    }

    private void SetAuditables()
    {
        IEnumerable<EntityEntry<IApiEntity>> entries = _context.ChangeTracker.Entries<IApiEntity>();
        foreach (EntityEntry<IApiEntity> entity in entries)
        {
            if (entity.State == EntityState.Added)
            {
                entity.Property(e => e.CreatedAt)
                    .CurrentValue = DateTime.Now;
            }

            if (entity.State == EntityState.Modified)
            {
                entity.Property(e => e.ModifiedAt)
                    .CurrentValue = DateTime.Now;
                if (_currentUserService.UserName != null)
                    entity.Property(e => e.ModifiedBy)
                        .CurrentValue = _currentUserService.UserName;
            }
        }
    }
    public void Dispose()
    {
        _currentTransaction?.Dispose();
        _context?.Dispose();
    }
}
