using Microsoft.EntityFrameworkCore; using Purrse.Core.DTOs; using Purrse.Core.Interfaces.Services; using Purrse.Core.Models; using Purrse.Data; namespace Purrse.Api.Services; public class AccountService : IAccountService { private readonly PurrseDbContext _db; public AccountService(PurrseDbContext db) { _db = db; } public async Task> GetAllAsync(Guid userId) { return await _db.Accounts .Where(a => a.UserId == userId) .OrderBy(a => a.SortOrder).ThenBy(a => a.Name) .Select(a => MapToResponse(a)) .ToListAsync(); } public async Task GetByIdAsync(Guid userId, Guid accountId) { var account = await _db.Accounts .Include(a => a.LoanDetail) .FirstOrDefaultAsync(a => a.Id == accountId && a.UserId == userId); return account == null ? null : MapToResponse(account); } public async Task CreateAsync(Guid userId, CreateAccountRequest request) { var account = new Account { Id = Guid.NewGuid(), UserId = userId, Name = request.Name, Type = request.Type, Institution = request.Institution, AccountNumber = request.AccountNumber, Balance = request.Balance, CreditLimit = request.CreditLimit, InterestRate = request.InterestRate, Notes = request.Notes, SortOrder = await _db.Accounts.CountAsync(a => a.UserId == userId) }; _db.Accounts.Add(account); await _db.SaveChangesAsync(); return MapToResponse(account); } public async Task UpdateAsync(Guid userId, Guid accountId, UpdateAccountRequest request) { var account = await _db.Accounts.FirstOrDefaultAsync(a => a.Id == accountId && a.UserId == userId) ?? throw new KeyNotFoundException("Account not found"); account.Name = request.Name; account.Institution = request.Institution; account.AccountNumber = request.AccountNumber; account.CreditLimit = request.CreditLimit; account.InterestRate = request.InterestRate; account.Notes = request.Notes; account.IsActive = request.IsActive; account.SortOrder = request.SortOrder; account.UpdatedAt = DateTime.UtcNow; await _db.SaveChangesAsync(); return MapToResponse(account); } public async Task DeleteAsync(Guid userId, Guid accountId) { var account = await _db.Accounts.FirstOrDefaultAsync(a => a.Id == accountId && a.UserId == userId) ?? throw new KeyNotFoundException("Account not found"); _db.Accounts.Remove(account); await _db.SaveChangesAsync(); } public async Task> GetBalanceHistoryAsync(Guid userId, Guid accountId, DateTime startDate, DateTime endDate) { var account = await _db.Accounts.FirstOrDefaultAsync(a => a.Id == accountId && a.UserId == userId) ?? throw new KeyNotFoundException("Account not found"); var transactions = await _db.Transactions .Where(t => t.AccountId == accountId && t.Date >= startDate && t.Date <= endDate && !t.IsVoid) .OrderBy(t => t.Date) .ToListAsync(); var balanceBefore = account.Balance - await _db.Transactions .Where(t => t.AccountId == accountId && !t.IsVoid) .SumAsync(t => t.Amount); var priorSum = await _db.Transactions .Where(t => t.AccountId == accountId && t.Date < startDate && !t.IsVoid) .SumAsync(t => t.Amount); var runningBalance = balanceBefore + priorSum; var entries = new List(); foreach (var group in transactions.GroupBy(t => t.Date.Date)) { runningBalance += group.Sum(t => t.Amount); entries.Add(new BalanceHistoryEntry(group.Key, runningBalance)); } return entries; } public async Task RecalculateBalanceAsync(Guid accountId) { var account = await _db.Accounts.FindAsync(accountId); if (account == null) return; var sum = await _db.Transactions .Where(t => t.AccountId == accountId && !t.IsVoid) .SumAsync(t => t.Amount); account.Balance = sum; account.UpdatedAt = DateTime.UtcNow; await _db.SaveChangesAsync(); } private static AccountResponse MapToResponse(Account a) => new( a.Id, a.Name, a.Type, a.Institution, a.AccountNumber, a.Balance, a.CreditLimit, a.InterestRate, a.IsActive, a.IsClosed, a.Notes, a.SortOrder, a.CreatedAt, a.LoanDetail != null ); }