using AMREZ.EOP.Abstractions.Applications.Tenancy; using AMREZ.EOP.Abstractions.Infrastructures.Repositories; using AMREZ.EOP.Abstractions.Storage; using AMREZ.EOP.Domain.Entities.HumanResources; using AMREZ.EOP.Domain.Entities.Tenancy; using AMREZ.EOP.Infrastructures.Data; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; namespace AMREZ.EOP.Infrastructures.Repositories; public class UserProfileRepository : IUserProfileRepository { private readonly IDbScope _scope; private readonly ITenantResolver _tenantResolver; private readonly IHttpContextAccessor _http; public UserProfileRepository(IDbScope scope, ITenantResolver tenantResolver, IHttpContextAccessor http) { _scope = scope; _tenantResolver = tenantResolver; _http = http; } private Guid TenantId() { var http = _http.HttpContext ?? throw new InvalidOperationException("No HttpContext"); var tc = _tenantResolver.Resolve(http) ?? throw new InvalidOperationException("No tenant"); _scope.EnsureForTenant(tc); if (!string.IsNullOrWhiteSpace(tc.Id) && Guid.TryParse(tc.Id, out var g) && g != Guid.Empty) return g; var key = (http.Items.TryGetValue("TargetTenantKey", out var v) ? v as string : null) ?? tc.TenantKey; if (string.IsNullOrWhiteSpace(key)) throw new InvalidOperationException("Tenant key missing"); var db = _scope.Get(); var cfg = db.Set().AsNoTracking().FirstOrDefault(x => x.TenantKey == key); if (cfg is null) throw new InvalidOperationException($"Tenant '{key}' not found"); return cfg.TenantId; } public async Task GetByUserIdAsync(Guid userId, CancellationToken ct = default) { var tid = TenantId(); var db = _scope.Get(); return await db.UserProfiles.FirstOrDefaultAsync(p => p.TenantId == tid && p.UserId == userId, ct); } public async Task UpsertAsync(UserProfile profile, CancellationToken ct = default) { var tid = TenantId(); var db = _scope.Get(); var existing = await db.UserProfiles.FirstOrDefaultAsync(p => p.TenantId == tid && p.UserId == profile.UserId, ct); if (existing is null) { profile.TenantId = tid; await db.UserProfiles.AddAsync(profile, ct); } else { existing.FirstName = profile.FirstName; existing.LastName = profile.LastName; existing.MiddleName = profile.MiddleName; existing.Nickname = profile.Nickname; existing.DateOfBirth = profile.DateOfBirth; existing.Gender = profile.Gender; } await db.SaveChangesAsync(ct); } public async Task AddEmploymentAsync(Employment e, CancellationToken ct = default) { var tid = TenantId(); var db = _scope.Get(); e.TenantId = tid; await db.Employments.AddAsync(e, ct); await db.SaveChangesAsync(ct); return e; } public async Task EndEmploymentAsync(Guid employmentId, DateTime endDate, CancellationToken ct = default) { var tid = TenantId(); var db = _scope.Get(); var e = await db.Employments.FirstOrDefaultAsync(x => x.TenantId == tid && x.Id == employmentId, ct); if (e is null) return; e.EndDate = endDate; await db.SaveChangesAsync(ct); } public async Task AddAddressAsync(EmployeeAddress a, CancellationToken ct = default) { var tid = TenantId(); var db = _scope.Get(); a.TenantId = tid; await db.EmployeeAddresses.AddAsync(a, ct); await db.SaveChangesAsync(ct); return a; } public async Task SetPrimaryAddressAsync(Guid userProfileId, Guid addressId, CancellationToken ct = default) { var tid = TenantId(); var db = _scope.Get(); var all = await db.EmployeeAddresses.Where(x => x.TenantId == tid && x.UserProfileId == userProfileId).ToListAsync(ct); foreach (var x in all) x.IsPrimary = false; var target = all.FirstOrDefault(x => x.Id == addressId); if (target is not null) target.IsPrimary = true; await db.SaveChangesAsync(ct); } public async Task AddEmergencyContactAsync(EmergencyContact c, CancellationToken ct = default) { var tid = TenantId(); var db = _scope.Get(); c.TenantId = tid; await db.EmergencyContacts.AddAsync(c, ct); await db.SaveChangesAsync(ct); return c; } public async Task SetPrimaryEmergencyContactAsync(Guid userProfileId, Guid contactId, CancellationToken ct = default) { var tid = TenantId(); var db = _scope.Get(); var all = await db.EmergencyContacts.Where(x => x.TenantId == tid && x.UserProfileId == userProfileId).ToListAsync(ct); foreach (var x in all) x.IsPrimary = false; var target = all.FirstOrDefault(x => x.Id == contactId); if (target is not null) target.IsPrimary = true; await db.SaveChangesAsync(ct); } public async Task AddBankAccountAsync(EmployeeBankAccount b, CancellationToken ct = default) { var tid = TenantId(); var db = _scope.Get(); b.TenantId = tid; await db.EmployeeBankAccounts.AddAsync(b, ct); await db.SaveChangesAsync(ct); return b; } public async Task SetPrimaryBankAccountAsync(Guid userProfileId, Guid bankAccountId, CancellationToken ct = default) { var tid = TenantId(); var db = _scope.Get(); var all = await db.EmployeeBankAccounts.Where(x => x.TenantId == tid && x.UserProfileId == userProfileId).ToListAsync(ct); foreach (var x in all) x.IsPrimary = false; var target = all.FirstOrDefault(x => x.Id == bankAccountId); if (target is not null) target.IsPrimary = true; await db.SaveChangesAsync(ct); } }