using CMSMicroservice.Protobuf.Protos.City; using CMSMicroservice.WebApi.Common.Services; using CMSMicroservice.Application.CityCQ.Queries.GetAllCitiesByFilter; using CMSMicroservice.Application.Common.Interfaces; using Microsoft.EntityFrameworkCore; using Google.Protobuf.WellKnownTypes; using System.Linq; namespace CMSMicroservice.WebApi.Services; public class CityService : CityContract.CityContractBase { private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS; private readonly IApplicationDbContext _context; public CityService(IDispatchRequestToCQRS dispatchRequestToCQRS, IApplicationDbContext context) { _dispatchRequestToCQRS = dispatchRequestToCQRS; _context = context; } public override async Task GetAllCitiesByFilter( GetAllCitiesByFilterRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle< GetAllCitiesByFilterRequest, GetAllCitiesByFilterQuery, GetAllCitiesByFilterResponse>(request, context); } #region Customer Methods public override async Task GetCitiesForCustomer( GetCitiesForCustomerRequest request, ServerCallContext context) { var pageNumber = request.PageNumber > 0 ? request.PageNumber : 1; var pageSize = request.PageSize > 0 ? request.PageSize : 50; var query = _context.Cities .Include(c => c.State) .Where(c => !c.IsDeleted); if (request.StateId != null) query = query.Where(c => c.StateId == request.StateId.Value); if (!string.IsNullOrWhiteSpace(request.SearchTerm)) query = query.Where(c => c.Name.Contains(request.SearchTerm) || c.Native.Contains(request.SearchTerm)); var totalCount = await query.CountAsync(context.CancellationToken); var cities = await query .OrderBy(c => c.Native) .Skip((pageNumber - 1) * pageSize) .Take(pageSize) .Select(c => new CityDto { Id = c.Id, ExternalId = c.ExternalId, Name = c.Name, Native = c.Native, Latitude = c.Latitude ?? string.Empty, Longitude = c.Longitude ?? string.Empty, StateId = c.StateId, StateName = c.State != null ? c.State.Name : string.Empty, StateNative = c.State != null ? c.State.Native : string.Empty }) .ToListAsync(context.CancellationToken); return new GetCitiesForCustomerResponse { Cities = { cities }, MetaData = new CMSMicroservice.Protobuf.Protos.City.MetaData { CurrentPage = pageNumber, PageSize = pageSize, TotalCount = totalCount, TotalPage = (int)Math.Ceiling(totalCount / (double)pageSize), HasNext = pageNumber * pageSize < totalCount, HasPrevious = pageNumber > 1 } }; } public override async Task GetCityByIdForCustomer( GetCityByIdForCustomerRequest request, ServerCallContext context) { var city = await _context.Cities .Include(c => c.State) .Where(c => c.Id == request.Id && !c.IsDeleted) .Select(c => new CityDto { Id = c.Id, ExternalId = c.ExternalId, Name = c.Name, Native = c.Native, Latitude = c.Latitude ?? string.Empty, Longitude = c.Longitude ?? string.Empty, StateId = c.StateId, StateName = c.State != null ? c.State.Name : string.Empty, StateNative = c.State != null ? c.State.Native : string.Empty }) .FirstOrDefaultAsync(context.CancellationToken); if (city == null) throw new RpcException(new Status(StatusCode.NotFound, "شهر یافت نشد")); return new GetCityByIdForCustomerResponse { City = city }; } public override async Task GetCitiesByStateForCustomer( GetCitiesByStateForCustomerRequest request, ServerCallContext context) { var pageNumber = request.PageNumber > 0 ? request.PageNumber : 1; var pageSize = request.PageSize > 0 ? request.PageSize : 100; var query = _context.Cities .Include(c => c.State) .Where(c => c.StateId == request.StateId && !c.IsDeleted); var totalCount = await query.CountAsync(context.CancellationToken); var cities = await query .OrderBy(c => c.Native) .Skip((pageNumber - 1) * pageSize) .Take(pageSize) .Select(c => new CityDto { Id = c.Id, ExternalId = c.ExternalId, Name = c.Name, Native = c.Native, Latitude = c.Latitude ?? string.Empty, Longitude = c.Longitude ?? string.Empty, StateId = c.StateId, StateName = c.State != null ? c.State.Name : string.Empty, StateNative = c.State != null ? c.State.Native : string.Empty }) .ToListAsync(context.CancellationToken); return new GetCitiesByStateForCustomerResponse { Cities = { cities }, MetaData = new CMSMicroservice.Protobuf.Protos.City.MetaData { CurrentPage = pageNumber, PageSize = pageSize, TotalCount = totalCount, TotalPage = (int)Math.Ceiling(totalCount / (double)pageSize), HasNext = pageNumber * pageSize < totalCount, HasPrevious = pageNumber > 1 } }; } // Admin Methods public override async Task CreateCity( CreateCityRequest request, ServerCallContext context) { var city = new Domain.Entities.Geography.City { ExternalId = request.ExternalId, Name = request.Name, Native = request.Native, Latitude = request.Latitude ?? string.Empty, Longitude = request.Longitude ?? string.Empty, StateId = request.StateId }; _context.Cities.Add(city); await _context.SaveChangesAsync(context.CancellationToken); return new CreateCityResponse { Id = city.Id, Message = "شهر با موفقیت ایجاد شد" }; } #region [ARCHIVED] UpdateCity & DeleteCity — شهرها seed data هستند، ویرایش/حذف دستی باعث خرابی آدرس‌ها می‌شود [Obsolete("ARCHIVED: Cities are seed data — manual edit/delete breaks user addresses")] public override async Task UpdateCity( UpdateCityRequest request, ServerCallContext context) { var city = await _context.Cities.FindAsync(new object[] { request.Id }, context.CancellationToken); if (city == null) throw new RpcException(new Status(StatusCode.NotFound, "شهر یافت نشد")); city.ExternalId = request.ExternalId; city.Name = request.Name; city.Native = request.Native; if (request.Latitude != null) city.Latitude = request.Latitude; if (request.Longitude != null) city.Longitude = request.Longitude; city.StateId = request.StateId; await _context.SaveChangesAsync(context.CancellationToken); return new Empty(); } [Obsolete("ARCHIVED: Cities are seed data — manual delete breaks user addresses")] public override async Task DeleteCity( DeleteCityRequest request, ServerCallContext context) { var city = await _context.Cities.FindAsync(new object[] { request.Id }, context.CancellationToken); if (city == null) throw new RpcException(new Status(StatusCode.NotFound, "شهر یافت نشد")); city.IsDeleted = true; await _context.SaveChangesAsync(context.CancellationToken); return new Empty(); } #endregion #endregion }