using System.Security.Claims; using Microsoft.EntityFrameworkCore; using ProposalSystem.Application.Interfaces; using ProposalSystem.Domain.Entities; using ProposalSystem.Infrastructure.Data; namespace ProposalSystem.Api.Services; public class CurrentUserService : ICurrentUserService { private readonly IHttpContextAccessor _httpContext; private readonly ProposalDbContext _db; private User? _cachedUser; public CurrentUserService(IHttpContextAccessor httpContext, ProposalDbContext db) { _httpContext = httpContext; _db = db; } public Guid UserId => GetUser().Id; public string Email => GetUser().Email; public UserRole Role => GetUser().Role; public string? IpAddress => _httpContext.HttpContext?.Connection.RemoteIpAddress?.ToString(); public async Task ResolveAsync() { if (_cachedUser != null) return; var principal = _httpContext.HttpContext?.User ?? throw new UnauthorizedAccessException("No authenticated user"); var userId = principal.FindFirstValue(ClaimTypes.NameIdentifier); var sub = principal.FindFirstValue("sub"); if (userId != null && Guid.TryParse(userId, out var parsedId)) { _cachedUser = await _db.Users.FirstOrDefaultAsync(u => u.Id == parsedId); } if (_cachedUser == null && sub != null) { _cachedUser = await _db.Users.FirstOrDefaultAsync(u => u.CognitoSub == sub); } if (_cachedUser == null) { var email = principal.FindFirstValue(ClaimTypes.Email) ?? principal.FindFirstValue("email") ?? "unknown@seahaven.com"; _cachedUser = await _db.Users.FirstOrDefaultAsync(u => u.Email == email); } if (_cachedUser == null) { var email = principal.FindFirstValue(ClaimTypes.Email) ?? principal.FindFirstValue("email") ?? "unknown@seahaven.com"; var name = principal.FindFirstValue("name") ?? email.Split('@')[0]; var groups = principal.FindAll("cognito:groups") .Select(c => c.Value).ToList(); var role = groups.Contains("sysadmins") ? UserRole.SysAdmin : groups.Contains("admins") ? UserRole.Admin : UserRole.Dispatcher; _cachedUser = new User { Id = Guid.NewGuid(), CognitoSub = sub ?? $"auto-{Guid.NewGuid():N}", Email = email, DisplayName = name, Role = role, IsActive = true, CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow, }; _db.Users.Add(_cachedUser); await _db.SaveChangesAsync(); } } private User GetUser() { if (_cachedUser != null) return _cachedUser; var principal = _httpContext.HttpContext?.User ?? throw new UnauthorizedAccessException("No authenticated user"); var userId = principal.FindFirstValue(ClaimTypes.NameIdentifier); var sub = principal.FindFirstValue("sub"); if (userId != null && Guid.TryParse(userId, out var parsedId)) { _cachedUser = _db.Users.FirstOrDefault(u => u.Id == parsedId); } if (_cachedUser == null && sub != null) { _cachedUser = _db.Users.FirstOrDefault(u => u.CognitoSub == sub); } if (_cachedUser == null) { var email = principal.FindFirstValue(ClaimTypes.Email) ?? principal.FindFirstValue("email") ?? "unknown@seahaven.com"; _cachedUser = _db.Users.FirstOrDefault(u => u.Email == email); } if (_cachedUser == null) { var email = principal.FindFirstValue(ClaimTypes.Email) ?? principal.FindFirstValue("email") ?? "unknown@seahaven.com"; var name = principal.FindFirstValue("name") ?? email.Split('@')[0]; var groups = principal.FindAll("cognito:groups") .Select(c => c.Value).ToList(); var role = groups.Contains("sysadmins") ? UserRole.SysAdmin : groups.Contains("admins") ? UserRole.Admin : UserRole.Dispatcher; _cachedUser = new User { Id = Guid.NewGuid(), CognitoSub = sub ?? $"auto-{Guid.NewGuid():N}", Email = email, DisplayName = name, Role = role, IsActive = true, CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow, }; _db.Users.Add(_cachedUser); _db.SaveChanges(); } return _cachedUser; } }