using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using QMax.Api.Contracts; using QMax.Api.Infrastructure.Max; namespace QMax.Api.Controllers; [ApiController] [Authorize] [Route("api/contacts")] public sealed class ContactsController(IMaxBridgeClient maxBridge) : ControllerBase { [HttpGet] public async Task>> GetContacts(CancellationToken cancellationToken) { var contacts = await maxBridge.FetchContactsAsync(cancellationToken); return contacts .Select(contact => new ContactDto( contact.UserId, contact.ExternalChatId, contact.DisplayName, contact.AvatarUrl, contact.PhoneNumber, contact.Status, contact.IsSavedContact)) .OrderBy(contact => contact.DisplayName, StringComparer.CurrentCultureIgnoreCase) .ToArray(); } [HttpPost("import")] public async Task>> ImportContacts( ImportPhoneContactsRequest request, CancellationToken cancellationToken) { var contacts = request.Contacts .Where(contact => !string.IsNullOrWhiteSpace(contact.PhoneNumber)) .Take(5000) .Select(contact => new MaxPhoneContact( contact.PhoneNumber.Trim(), string.IsNullOrWhiteSpace(contact.FirstName) ? contact.PhoneNumber.Trim() : contact.FirstName.Trim(), contact.LastName?.Trim())) .ToArray(); if (contacts.Length == 0) { return BadRequest("contacts with phone numbers are required."); } var imported = await maxBridge.ImportContactsAsync(contacts, cancellationToken); return imported.Select(ToDto).ToArray(); } [HttpPost("add")] public async Task> AddContact(ContactUserRequest request, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(request.UserId)) { return BadRequest("userId is required."); } var contact = await maxBridge.AddContactAsync(request.UserId.Trim(), cancellationToken); return contact is null ? BadRequest("MAX did not add the contact.") : ToDto(contact); } [HttpPost("remove")] public async Task RemoveContact(ContactUserRequest request, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(request.UserId)) { return BadRequest("userId is required."); } var result = await maxBridge.RemoveContactAsync(request.UserId.Trim(), cancellationToken); return result.Success ? NoContent() : BadRequest(result.Error ?? "MAX did not remove the contact."); } private static ContactDto ToDto(MaxContact contact) => new( contact.UserId, contact.ExternalChatId, contact.DisplayName, contact.AvatarUrl, contact.PhoneNumber, contact.Status, contact.IsSavedContact); }