using Dapper;
using Dapper.Contrib.Extensions;

using System.Data;

namespace FabApprovalWorkerService.Services;
public interface IDalService {
    Task<IEnumerable<T>> QueryAsync<T>(string sql);
    Task<bool> UpdateAsync<T>(ICollection<T> collection);
}

public class DalService : IDalService {
    private readonly IDbConnection _dbConnection;
    private readonly ILogger<DalService> _logger;

    public DalService(IDbConnection dbConnection, ILogger<DalService> logger) {
        _dbConnection = dbConnection;
        if (_dbConnection is null) throw new ArgumentNullException("IDbConnection not injected");
        _logger = logger;
        if (_logger is null) throw new ArgumentNullException("ILogger not injected");
    }

    public async Task<IEnumerable<T>> QueryAsync<T>(string sql) {
        if (sql is null) throw new ArgumentNullException("sql cannot be null");
        try {
            _logger.LogInformation("Attempting to perform query with {sql}", sql);

            _dbConnection.Open();
            return await _dbConnection.QueryAsync<T>(sql);
        } catch (Exception ex) {
            _logger.LogError("An exception occurred while attempting to perform a query. Exception: {ex}",
                             ex.Message);

            throw;
        } finally {
            _dbConnection.Close();
        }
    }

    public async Task<bool> UpdateAsync<T>(ICollection<T> collection) {
        if (collection is null) throw new ArgumentNullException("collection cannot be null");
        try {
            _logger.LogInformation("Attempting to perform a bulk update");

            _dbConnection.Open();
            return await _dbConnection.UpdateAsync<ICollection<T>>(collection);
        } catch (Exception ex) {
            _logger.LogError("An exception occurred while attempting to perform a bulk update. Exception: {ex}",
                             ex.Message);

            throw;
        } finally {
            _dbConnection.Close();
        }
    }
}
