using LiteCharms.Features.Extensions; using LiteCharms.Features.Models; using LiteCharms.Features.TechShop.Customers.Models; using LiteCharms.Features.TechShop.Extensions; using LiteCharms.Features.TechShop.Postgres; namespace LiteCharms.Features.TechShop.Customers; public class CustomerService(IDbContextFactory contextFactory) { public async ValueTask> CreateCustomerAsync(CreateCustomer request, CancellationToken cancellationToken = default) { try { using var context = await contextFactory.CreateDbContextAsync(cancellationToken); var customerEmail = request.Email.ToLower().Trim(); if (await context.Customers.AnyAsync(c => c.Email == customerEmail, cancellationToken)) return Result.Fail(new Error($"A customer with the email {customerEmail} already exists")); var newCustomer = context.Customers.Add(new Entities.Customer { Company = request.Company, Name = request.Name, LastName = request.LastName, Tax = request.Tax, Email = customerEmail, Discord = request.Discord, Slack = request.Slack, LinkedIn = request.LinkedIn, Whatsapp = request.Whatsapp, Website = request.Website, Phone = request.Phone, Address = request.Address, City = request.City, Region = request.Region, Country = request.Country, PostalCode = request.PostalCode, Active = true, }); return await context.SaveChangesAsync(cancellationToken) > 0 ? Result.Ok(newCustomer.Entity.Id) : Result.Fail(new Error($"Failed to create customer {customerEmail}")); } catch (Exception ex) { return Result.Fail(new Error(ex.Message).CausedBy(ex)); } } public async ValueTask> GetCustomerAsync(Guid customerId, CancellationToken cancellationToken = default) { try { using var context = await contextFactory.CreateDbContextAsync(cancellationToken); var customer = await context.Customers.FirstOrDefaultAsync(c => c.Id == customerId, cancellationToken); return customer is not null ? Result.Ok(customer.ToModel()) : Result.Fail($"Customer not found with id {customerId}"); } catch (Exception ex) { return Result.Fail(new Error(ex.Message).CausedBy(ex)); } } public async ValueTask> GetCustomersAsync(DateRange range, CancellationToken cancellationToken = default) { try { var fromDate = range.From.ToDateTime(TimeOnly.MinValue); var toDate = range.To.ToDateTime(TimeOnly.MaxValue); using var context = await contextFactory.CreateDbContextAsync(cancellationToken); var customers = await context.Customers.AsNoTracking() .OrderByDescending(o => o.CreatedAt) .Where(c => c.CreatedAt >= fromDate && c.CreatedAt <= toDate) .Take(range.MaxRecords) .ToArrayAsync(cancellationToken); return customers?.Length > 0 ? Result.Ok(customers.Select(c => c.ToModel()).ToArray()) : Result.Fail(new Error("No customers found in the specified date range.")); } catch (Exception ex) { return Result.Fail(new Error(ex.Message).CausedBy(ex)); } } public async ValueTask UpdateCustomerAsync(UpdateCustomer request, CancellationToken cancellationToken = default) { try { using var context = await contextFactory.CreateDbContextAsync(cancellationToken); var customer = await context.Customers.FirstOrDefaultAsync(c => c.Id == request.CustomerId, cancellationToken); if (customer is null) return Result.Fail(new Error($"Customer with ID {request.CustomerId} not found.")); customer.Name = request.Name; customer.LastName = request.LastName; customer.Email = request.Email; customer.Company = request.Company; customer.Address = request.Address; customer.City = request.City; customer.Region = request.Region; customer.Country = request.Country; customer.PostalCode = request.PostalCode; customer.Phone = request.Phone; customer.Tax = request.Tax; customer.City = request.City; customer.Discord = request.Discord; customer.Slack = request.Slack; customer.LinkedIn = request.LinkedIn; customer.Whatsapp = request.Whatsapp; return await context.SaveChangesAsync(cancellationToken) > 0 ? Result.Ok() : Result.Fail(new Error($"Failed to update the customer {request.CustomerId}.")); } catch (Exception ex) { return Result.Fail(new Error(ex.Message).CausedBy(ex)); } } }