using gehGassi.Core.Interfaces;
using gehGassi.Domain.Pages;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using gehGassi.Domain.Coins;
using gehGassi.Domain.Common;
using gehGassi.Domain.Walks;
using Microsoft.EntityFrameworkCore;
namespace gehGassi.Core.Services
{
///
/// Service der die Verwaltung von Coin-Konten, Transaktionen und Monats- und Jahresstatistiken realisiert
///
public class CoinsService : ServiceBase, ICoinsService
{
private readonly IRepository _transactionRepository;
private readonly IRepository _perMonthRepository;
private readonly IRepository _perMonthNamesRepository;
private readonly IRepository _perYearRepository;
private readonly IRepository _perYearNamesRepository;
///
/// Erstellt eine Instanz
///
/// Instanz eines IUnitOfWork
public CoinsService(IUnitOfWork unitOfWork) : base(unitOfWork)
{
_transactionRepository = unitOfWork.GetRepository();
_perMonthRepository = unitOfWork.GetRepository();
_perMonthNamesRepository = unitOfWork.GetRepository();
_perYearRepository = unitOfWork.GetRepository();
_perYearNamesRepository = unitOfWork.GetRepository();
}
///
/// Gibt einen Coin-Account zurück oder erstellt einen neuen wenn noch nicht vorhanden
///
/// Id des AppUsers
/// Typ des AppUsers
/// CoinAccount
public async Task GetOrCreateAsync(string appUserId, AppUserType appUserType)
{
var account = await Repository.FirstOrDefaultAsync(c => c.AppUserId == appUserId && c.AppUserType == appUserType);
if (account == null)
{
account = new CoinsAccount()
{
Id = Guid.NewGuid().ToString("N"),
AppUserId = appUserId,
AppUserType = appUserType,
Balance = 0,
Created = DateTimeOffset.UtcNow,
UpdatedAt = DateTimeOffset.UtcNow
};
Repository.Add(account);
await CommitAsync("System");
}
return account;
}
///
/// Einzahlen einer Coins-Summe auf das passende Konto eines AppUsers
///
/// Id des AppUsers
/// Typ des AppUsers
/// Coins-Betrag der eingezahlt werden soll
/// Optional: Id des Walks auf den sich die Transaktion bezieht
/// Transaktion
public async Task DepositAsync(string appUserId, AppUserType appUserType, decimal ammount, string walkId)
{
var account = await GetOrCreateAsync(appUserId, appUserType);
//Transaktion anlegen
var transaction = new CoinsTransaction()
{
TransactionType = CoinsTransactionType.Deposit,
AccountId = account.Id,
Ammount = ammount,
WalkId = walkId,
Created = DateTimeOffset.UtcNow
};
_transactionRepository.Add(transaction);
account.Balance += ammount;
//Punkte für das Monatskonto
var coinsPerMonth = await GetOrCreateCoinsPerMonthAsync(appUserId, appUserType, DateTimeOffset.UtcNow);
coinsPerMonth.Balance += ammount;
coinsPerMonth.LastUpdate = DateTimeOffset.UtcNow;
//Punkte für das Jahreskonto
var coinsPerYear = await GetOrCreateCoinsPerYearAsync(appUserId, appUserType, DateTimeOffset.UtcNow);
coinsPerYear.Balance += ammount;
coinsPerYear.LastUpdate = DateTimeOffset.UtcNow;
await CommitAsync("System");
return transaction;
}
///
/// Abbuchen einer Coins-Summe von dem passenden Konto eines AppUsers
///
/// Id des AppUsers
/// Typ des AppUsers
/// Coins-Betrag der eingezahlt werden soll
/// CoinsTransaction
public async Task WithdrawAsync(string appUserId, AppUserType appUserType, decimal ammount)
{
var account = await GetOrCreateAsync(appUserId, appUserType);
if (account.Balance < ammount)
return null;
//Transaktion anlegen
var transaction = new CoinsTransaction()
{
TransactionType = CoinsTransactionType.Withdrawal,
AccountId = account.Id,
Ammount = ammount,
WalkId = string.Empty,
Created = DateTimeOffset.UtcNow
};
_transactionRepository.Add(transaction);
account.Balance -= ammount;
await CommitAsync("System");
return transaction;
}
///
/// Gibt den Coins-Stand eines AppUsers für einen Monat zurück
///
/// Id des AppUsers
/// Typ des AppUsers
/// Datum
/// CoinsPerMonth
public async Task GetOrCreateCoinsPerMonthAsync(string appUserId, AppUserType appUserType, DateTimeOffset date)
{
var coinsPerMonth = await _perMonthRepository.FirstOrDefaultAsync(c => c.AppUserId == appUserId && c.AppUserType == appUserType && c.Year == date.Year && c.Month == date.Month);
if (coinsPerMonth == null)
{
coinsPerMonth = new CoinsPerMonth()
{
AppUserId = appUserId,
AppUserType = appUserType,
Year = date.Year,
Month = date.Month,
Balance = 0,
LastUpdate = DateTimeOffset.UtcNow
};
//Keine Wertung rückwirkend erstellen
if (date.Year == DateTimeOffset.UtcNow.Year && date.Month == DateTimeOffset.UtcNow.Month)
{
_perMonthRepository.Add(coinsPerMonth);
await CommitAsync("System");
}
}
return coinsPerMonth;
}
///
/// Gibt den Coins-Stand eines AppUsers für ein Jahr zurück
///
/// Id des AppUsers
/// Typ des AppUsers
/// Datum
/// CoinsPerYear
public async Task GetOrCreateCoinsPerYearAsync(string appUserId, AppUserType appUserType, DateTimeOffset date)
{
var coinsPerYear = await _perYearRepository.FirstOrDefaultAsync(c => c.AppUserId == appUserId && c.AppUserType == appUserType && c.Year == date.Year);
if (coinsPerYear == null)
{
coinsPerYear = new CoinsPerYear()
{
AppUserId = appUserId,
AppUserType = appUserType,
Year = date.Year,
Balance = 0,
LastUpdate = DateTimeOffset.UtcNow
};
//Keine Wertung rückwirkend erstellen
if (date.Year == DateTimeOffset.UtcNow.Year)
{
_perYearRepository.Add(coinsPerYear);
await CommitAsync("System");
}
}
return coinsPerYear;
}
///
/// Gibt die Top X der Coins je Monat für ein Jahr und Monat zurück.
/// Sortiert nach Coins absteigend und bei Gleichstand nach LastUpdate aufsteigend
///
/// Anzalh Datensätze
/// Typ des AppUsers
/// Jahr
/// Monat
/// Mindest-Wert der erreicht werden musste
/// Liste CoinsPerMonthWithNames
public async Task> GetMonthlyTopAsync(int count, AppUserType appUserType, int year, int month, decimal minBalance)
{
var coins = await _perMonthNamesRepository.QueryView(c => c.AppUserType == appUserType && c.Year == year && c.Month == month && c.Balance >= minBalance).OrderByDescending(c => c.Balance).ThenBy(c => c.LastUpdate).Take(count).ToListAsync();
return coins;
}
///
/// Gibt die Top X der Coins je Jahr zurück.
/// Sortiert nach Coins absteigend und bei Gleichstand nach LastUpdate aufsteigend
///
/// Anzalh Datensätze
/// Typ des AppUsers
/// Jahr
/// Mindest-Wert der erreicht werden musste
/// Liste CoinsPerMonthWithNames
public async Task> GetYearlyTopAsync(int count, AppUserType appUserType, int year, decimal minBalance)
{
var coins = await _perYearNamesRepository.QueryView(c => c.AppUserType == appUserType && c.Year == year && c.Balance >= minBalance).OrderByDescending(c => c.Balance).ThenBy(c => c.LastUpdate).Take(count).ToListAsync();
return coins;
}
}
}