|
- using System.Collections.Concurrent;
-
- namespace Campaign_Tracker.Server.Municipalities;
-
- public sealed class InMemoryMunicipalityContactRepository : IMunicipalityContactRepository
- {
- private static readonly Dictionary<string, int> ContactTypeSortOrder =
- new(StringComparer.OrdinalIgnoreCase)
- {
- ["Primary"] = 0,
- ["Secondary"] = 1,
- };
-
- private readonly ConcurrentDictionary<string, MunicipalityContact> _contacts =
- new(StringComparer.OrdinalIgnoreCase);
- private readonly object _lock = new();
- private readonly TimeProvider _timeProvider;
-
- public InMemoryMunicipalityContactRepository(TimeProvider timeProvider)
- {
- _timeProvider = timeProvider;
- }
-
- public Task<IReadOnlyList<MunicipalityContact>> GetByProfileIdAsync(
- string profileId,
- CancellationToken cancellationToken = default)
- {
- var result = _contacts.Values
- .Where(c => c.ProfileId == profileId && !c.IsDeleted)
- .OrderBy(c => ContactTypeSortOrder.GetValueOrDefault(c.ContactType, 99))
- .ThenBy(c => c.Name, StringComparer.OrdinalIgnoreCase)
- .ToArray();
- return Task.FromResult<IReadOnlyList<MunicipalityContact>>(result);
- }
-
- public Task<MunicipalityContact?> GetByIdAsync(
- string contactId,
- CancellationToken cancellationToken = default)
- {
- _contacts.TryGetValue(contactId, out var contact);
- return Task.FromResult(contact is { IsDeleted: false } ? contact : null);
- }
-
- public Task<MunicipalityContactSaveResult> AddAsync(
- string profileId,
- string contactType,
- string name,
- string? roleTitle,
- string? phone,
- string? email,
- string actorIdentity,
- CancellationToken cancellationToken = default)
- {
- var validation = Validate(contactType, name);
- if (validation is not null)
- return Task.FromResult(MunicipalityContactSaveResult.Failure(validation));
-
- var now = _timeProvider.GetUtcNow();
- var contact = new MunicipalityContact(
- ContactId: Guid.NewGuid().ToString("N"),
- ProfileId: profileId,
- ContactType: NormalizeContactType(contactType),
- Name: name.Trim(),
- RoleTitle: NormalizeOptional(roleTitle),
- Phone: NormalizeOptional(phone),
- Email: NormalizeOptional(email),
- IsDeleted: false,
- CreatedAt: now,
- CreatedBy: actorIdentity,
- UpdatedAt: now,
- UpdatedBy: actorIdentity);
-
- _contacts[contact.ContactId] = contact;
- return Task.FromResult(MunicipalityContactSaveResult.Success(contact));
- }
-
- public Task<MunicipalityContactSaveResult> UpdateAsync(
- string contactId,
- string contactType,
- string name,
- string? roleTitle,
- string? phone,
- string? email,
- string actorIdentity,
- CancellationToken cancellationToken = default)
- {
- var validation = Validate(contactType, name);
- if (validation is not null)
- return Task.FromResult(MunicipalityContactSaveResult.Failure(validation));
-
- var now = _timeProvider.GetUtcNow();
-
- lock (_lock)
- {
- if (!_contacts.TryGetValue(contactId, out var existing) || existing.IsDeleted)
- return Task.FromResult(MunicipalityContactSaveResult.NotFound(contactId));
-
- var updated = existing with
- {
- ContactType = NormalizeContactType(contactType),
- Name = name.Trim(),
- RoleTitle = NormalizeOptional(roleTitle),
- Phone = NormalizeOptional(phone),
- Email = NormalizeOptional(email),
- UpdatedAt = now,
- UpdatedBy = actorIdentity,
- };
- _contacts[contactId] = updated;
- return Task.FromResult(MunicipalityContactSaveResult.Success(updated));
- }
- }
-
- public Task<MunicipalityContactSaveResult> SoftDeleteAsync(
- string contactId,
- string actorIdentity,
- CancellationToken cancellationToken = default)
- {
- var now = _timeProvider.GetUtcNow();
-
- lock (_lock)
- {
- if (!_contacts.TryGetValue(contactId, out var existing) || existing.IsDeleted)
- return Task.FromResult(MunicipalityContactSaveResult.NotFound(contactId));
-
- var deleted = existing with
- {
- IsDeleted = true,
- UpdatedAt = now,
- UpdatedBy = actorIdentity,
- };
- _contacts[contactId] = deleted;
- return Task.FromResult(MunicipalityContactSaveResult.Success(deleted));
- }
- }
-
- private static string? Validate(string contactType, string name)
- {
- if (string.IsNullOrWhiteSpace(name))
- return "Name is required.";
-
- if (string.IsNullOrWhiteSpace(contactType))
- return "Contact type is required.";
-
- if (!ContactTypeSortOrder.ContainsKey(contactType.Trim()))
- return "Contact type must be Primary or Secondary.";
-
- return null;
- }
-
- private static string NormalizeContactType(string contactType) =>
- string.Equals(contactType.Trim(), "Primary", StringComparison.OrdinalIgnoreCase)
- ? "Primary"
- : "Secondary";
-
- private static string? NormalizeOptional(string? value) =>
- string.IsNullOrWhiteSpace(value) ? null : value.Trim();
- }
|