using AutoMapper; using GreenHome.Application; using Microsoft.EntityFrameworkCore; namespace GreenHome.Infrastructure; public sealed class DevicePostService : IDevicePostService { private readonly GreenHomeDbContext _context; private readonly IMapper _mapper; public DevicePostService(GreenHomeDbContext context, IMapper mapper) { _context = context; _mapper = mapper; } public async Task> GetPostsAsync( DevicePostFilter filter, CancellationToken cancellationToken) { var query = _context.DevicePosts .Include(p => p.AuthorUser) .Include(p => p.Images) .AsNoTracking() .Where(p => p.DeviceId == filter.DeviceId); if (filter.AuthorUserId.HasValue) { query = query.Where(p => p.AuthorUserId == filter.AuthorUserId.Value); } var totalCount = await query.CountAsync(cancellationToken); var posts = await query .OrderByDescending(p => p.CreatedAt) .Skip((filter.Page - 1) * filter.PageSize) .Take(filter.PageSize) .ToListAsync(cancellationToken); var dtos = _mapper.Map>(posts); return new PagedResult { Items = dtos, TotalCount = totalCount, Page = filter.Page, PageSize = filter.PageSize }; } public async Task GetPostByIdAsync(int id, CancellationToken cancellationToken) { var post = await _context.DevicePosts .Include(p => p.AuthorUser) .Include(p => p.Images) .AsNoTracking() .FirstOrDefaultAsync(p => p.Id == id, cancellationToken); return post != null ? _mapper.Map(post) : null; } public async Task CreatePostAsync( CreateDevicePostRequest request, CancellationToken cancellationToken) { // Verify user has access to device var hasAccess = await CanUserAccessDeviceAsync(request.AuthorUserId, request.DeviceId, cancellationToken); if (!hasAccess) { throw new UnauthorizedAccessException("کاربر به این دستگاه دسترسی ندارد"); } var post = new Domain.DevicePost { DeviceId = request.DeviceId, AuthorUserId = request.AuthorUserId, Content = request.Content, CreatedAt = DateTime.UtcNow }; _context.DevicePosts.Add(post); await _context.SaveChangesAsync(cancellationToken); return post.Id; } public async Task UpdatePostAsync( UpdateDevicePostRequest request, CancellationToken cancellationToken) { var post = await _context.DevicePosts .FirstOrDefaultAsync(p => p.Id == request.Id, cancellationToken); if (post == null) { throw new InvalidOperationException($"پست با شناسه {request.Id} یافت نشد"); } post.Content = request.Content; post.UpdatedAt = DateTime.UtcNow; await _context.SaveChangesAsync(cancellationToken); } public async Task DeletePostAsync(int id, CancellationToken cancellationToken) { var post = await _context.DevicePosts .Include(p => p.Images) .FirstOrDefaultAsync(p => p.Id == id, cancellationToken); if (post == null) { throw new InvalidOperationException($"پست با شناسه {id} یافت نشد"); } _context.DevicePosts.Remove(post); await _context.SaveChangesAsync(cancellationToken); } public async Task AddImageToPostAsync( int postId, string fileName, string filePath, string contentType, long fileSize, CancellationToken cancellationToken) { var post = await _context.DevicePosts .FirstOrDefaultAsync(p => p.Id == postId, cancellationToken); if (post == null) { throw new InvalidOperationException($"پست با شناسه {postId} یافت نشد"); } var image = new Domain.DevicePostImage { DevicePostId = postId, FileName = fileName, FilePath = filePath, ContentType = contentType, FileSize = fileSize, UploadedAt = DateTime.UtcNow }; _context.DevicePostImages.Add(image); await _context.SaveChangesAsync(cancellationToken); return image.Id; } public async Task DeleteImageAsync(int imageId, CancellationToken cancellationToken) { var image = await _context.DevicePostImages .FirstOrDefaultAsync(i => i.Id == imageId, cancellationToken); if (image == null) { throw new InvalidOperationException($"تصویر با شناسه {imageId} یافت نشد"); } _context.DevicePostImages.Remove(image); await _context.SaveChangesAsync(cancellationToken); } public async Task CanUserAccessDeviceAsync( int userId, int deviceId, CancellationToken cancellationToken) { // Check if user is the device owner or has access through DeviceUsers var hasAccess = await _context.Devices .AnyAsync(d => d.Id == deviceId && d.UserId == userId, cancellationToken); if (!hasAccess) { hasAccess = await _context.DeviceUsers .AnyAsync(du => du.DeviceId == deviceId && du.UserId == userId, cancellationToken); } return hasAccess; } }