using Fitness_core_BE.DTOs.Place; using Fitness_core_BE.Helpers; using Fitness_core_BE.Infra.UoW; using Fitness_core_BE.Interfaces; using Fitness_core_BE.Interfaces.Services; using Fitness_core_BE.Models; using System.Text.Json; namespace Fitness_core_BE.Services { public class PlaceService : IPlaceService { private readonly IPlaceRepo _placeRepo; private readonly IUnitOfWork _uow; private readonly UserRoleHelper _userRoleHelper; public PlaceService(IPlaceRepo placeRepo, IUnitOfWork uow, UserRoleHelper userRoleHelper) { _placeRepo = placeRepo; _uow = uow; _userRoleHelper = userRoleHelper; } public async Task GetAllPlaces(object payload, HttpContext httpContext) { var data = DeserializePayload.Deserialize(payload); bool includeInactive = data.ContainsKey("includeInactive") && data["includeInactive"].GetBoolean(); var clientId = await _userRoleHelper.GetClientId(DataExtractor.GetUserIdFromContext(httpContext)); var places = await _placeRepo.GetAllPlaces(clientId, includeInactive); var devicesByPlace = await _placeRepo.GetDevicesByPlaceIdsAsync(places.Select(p => p.PlaceId).ToList()); return places.Select(p => MapToDto(p, devicesByPlace.GetValueOrDefault(p.PlaceId))).ToList(); } public async Task CreatePlace(object payload, HttpContext httpContext) { await _uow.BeginAsync(); try { var data = DeserializePayload.Deserialize(payload); if (!data.ContainsKey("name")) throw new KeyNotFoundException("name is required"); var clientId = await _userRoleHelper.GetClientId(DataExtractor.GetUserIdFromContext(httpContext)); var place = new Place { FKClientId = clientId, Name = data["name"].GetString() ?? "", Description = data.ContainsKey("description") ? data["description"].GetString() : null }; var result = await _placeRepo.CreatePlace(place); await _uow.CommitAsync(); return MapToDto(result, null); } catch { await _uow.RollbackAsync(); throw; } } public async Task UpdatePlace(object payload, HttpContext httpContext) { await _uow.BeginAsync(); try { var data = DeserializePayload.Deserialize(payload); if (!data.ContainsKey("placeId")) throw new KeyNotFoundException("placeId is required"); var placeId = Guid.Parse(data["placeId"].GetString()!); var existing = await _placeRepo.GetPlaceById(placeId) ?? throw new KeyNotFoundException("Place not found"); if (data.ContainsKey("name")) existing.Name = data["name"].GetString() ?? existing.Name; if (data.ContainsKey("description")) existing.Description = data["description"].GetString(); if (data.ContainsKey("isActive")) existing.IsActive = data["isActive"].GetBoolean(); var result = await _placeRepo.UpdatePlace(existing); await _uow.CommitAsync(); var devicesByPlace = await _placeRepo.GetDevicesByPlaceIdsAsync(new List { result.PlaceId }); return MapToDto(result, devicesByPlace.GetValueOrDefault(result.PlaceId)); } catch { await _uow.RollbackAsync(); throw; } } public async Task SetPlaceStatus(object payload, HttpContext httpContext) { await _uow.BeginAsync(); try { var data = DeserializePayload.Deserialize(payload); var placeId = Guid.Parse(data["placeId"].GetString()!); var isActive = data["isActive"].GetBoolean(); var clientId = await _userRoleHelper.GetClientId(DataExtractor.GetUserIdFromContext(httpContext)); var place = await _placeRepo.SetPlaceActive(placeId, clientId, isActive) ?? throw new KeyNotFoundException("Place not found"); await _uow.CommitAsync(); var devicesByPlace = await _placeRepo.GetDevicesByPlaceIdsAsync(new List { place.PlaceId }); return MapToDto(place, devicesByPlace.GetValueOrDefault(place.PlaceId)); } catch { await _uow.RollbackAsync(); throw; } } public async Task AssignDevice(object payload, HttpContext httpContext) { await _uow.BeginAsync(); try { var data = DeserializePayload.Deserialize(payload); if (!data.ContainsKey("placeId")) throw new KeyNotFoundException("placeId is required"); var placeId = Guid.Parse(data["placeId"].GetString()!); var clientId = await _userRoleHelper.GetClientId(DataExtractor.GetUserIdFromContext(httpContext)); var place = await _placeRepo.GetPlaceById(placeId); if (place == null || place.FKClientId != clientId) throw new KeyNotFoundException("Place not found"); var hasDeviceId = data.ContainsKey("deviceId") && data["deviceId"].ValueKind != JsonValueKind.Null; if (!hasDeviceId) { await _placeRepo.UnassignDeviceAsync(placeId); } else { var deviceId = Guid.Parse(data["deviceId"].GetString()!); var device = await _placeRepo.GetDeviceByIdForClientAsync(deviceId, clientId) ?? throw new KeyNotFoundException("Device not found"); if (await _placeRepo.IsDeviceAssignedToAnotherPlaceAsync(deviceId, placeId)) throw new ArgumentException("This device is already assigned to another place."); await _placeRepo.AssignDeviceAsync(placeId, deviceId); } await _uow.CommitAsync(); var devicesByPlace = await _placeRepo.GetDevicesByPlaceIdsAsync(new List { placeId }); return MapToDto(place, devicesByPlace.GetValueOrDefault(placeId)); } catch { await _uow.RollbackAsync(); throw; } } private static PlaceDto MapToDto(Place place, AccessDevice? device) => new() { PlaceId = place.PlaceId, Name = place.Name, Description = place.Description, IsActive = place.IsActive, CreatedAt = place.CreatedAt, DeviceId = device?.DeviceId, DeviceName = device?.DeviceName }; } }