using Ardalis.Result; using Microsoft.EntityFrameworkCore; using SimpleToolkit.Extensions; using WatchIt.Database.Model.Accounts; using WatchIt.Database.Model.Genres; using WatchIt.Database.Model.Media; using WatchIt.Database.Model.Photos; using WatchIt.Database.Model.Roles; using WatchIt.DTO.Models.Controllers.Genres; using WatchIt.DTO.Models.Controllers.Genres.Genre; using WatchIt.DTO.Models.Controllers.Media; using WatchIt.DTO.Models.Controllers.Media.Medium; using WatchIt.DTO.Models.Controllers.Media.Medium.Query; using WatchIt.DTO.Models.Controllers.Media.Medium.Request; using WatchIt.DTO.Models.Controllers.Media.Medium.Response; using WatchIt.DTO.Models.Controllers.Photos; using WatchIt.DTO.Models.Controllers.Photos.Photo; using WatchIt.DTO.Models.Controllers.Roles; using WatchIt.DTO.Models.Controllers.Roles.Role.Response; using WatchIt.DTO.Models.Generics.Image; using WatchIt.DTO.Models.Generics.Rating; using WatchIt.DTO.Query; using WatchIt.WebAPI.Repositories.Genres; using WatchIt.WebAPI.Repositories.Media; using WatchIt.WebAPI.Repositories.Photos; using WatchIt.WebAPI.Services.User; namespace WatchIt.WebAPI.BusinessLogic.Media; public class MediaBusinessLogic : IMediaBusinessLogic { #region SERVICES private readonly IUserService _userService; private readonly IMediaRepository _mediaRepository; private readonly IGenresRepository _genresRepository; private readonly IPhotosRepository _photosRepository; #endregion #region CONSTRUCTORS public MediaBusinessLogic(IUserService userService, IMediaRepository mediaRepository, IGenresRepository genresRepository, IPhotosRepository photosRepository) { _userService = userService; _mediaRepository = mediaRepository; _genresRepository = genresRepository; _photosRepository = photosRepository; } #endregion #region PUBLIC METHODS #region Main public async Task>> GetMedia(MediumFilterQuery filterQuery, OrderQuery orderQuery, PagingQuery pagingQuery, bool includePictures) { IEnumerable entities = await _mediaRepository.GetAllAsync(filterQuery, orderQuery, pagingQuery, x => IncludeForMediumResponse(x, includePictures)); return Result.Success(entities.Select(x => x.ToResponse())); } public async Task> GetMedium(long mediumId, bool includePictures) { Medium? entity = await _mediaRepository.GetAsync(mediumId, x => IncludeForMediumResponse(x, includePictures)); return entity switch { null => Result.NotFound(), _ => Result.Success(entity.ToResponse()) }; } public async Task>> GetMediumMovies(MediumMovieFilterQuery filterQuery, OrderQuery orderQuery, PagingQuery pagingQuery, bool includePictures) { IEnumerable entities = await _mediaRepository.GetAllMoviesAsync(filterQuery, orderQuery, pagingQuery, x => IncludeForMediumResponse(x, includePictures)); return Result.Success(entities.Select(x => x.ToResponse())); } public async Task> GetMediumMovie(long mediumId, bool includePictures) { MediumMovie? entity = await _mediaRepository.GetAsync(mediumId, x => IncludeForMediumResponse(x, includePictures)); return entity switch { null => Result.NotFound(), _ => Result.Success(entity.ToResponse()), }; } public async Task>> GetMediumSeries(MediumSeriesFilterQuery filterQuery, OrderQuery orderQuery, PagingQuery pagingQuery, bool includePictures) { IEnumerable entities = await _mediaRepository.GetAllSeriesAsync(filterQuery, orderQuery, pagingQuery, x => IncludeForMediumResponse(x, includePictures)); return Result.Success(entities.Select(x => x.ToResponse())); } public async Task> GetMediumSeries(long mediumId, bool includePictures) { MediumSeries? entity = await _mediaRepository.GetAsync(mediumId, x => IncludeForMediumResponse(x, includePictures)); return entity switch { null => Result.NotFound(), _ => Result.Success(entity.ToResponse()), }; } public async Task> PostMediumMovie(MediumMovieRequest body) { MediumMovie entity = body.ToEntity(); await _mediaRepository.AddAsync(entity); return Result.Created(entity.ToResponse()); } public async Task> PostMediumSeries(MediumSeriesRequest body) { MediumSeries entity = body.ToEntity(); await _mediaRepository.AddAsync(entity); return Result.Created(entity.ToResponse()); } public async Task> PutMediumMovie(long mediumId, MediumMovieRequest body) { return await _mediaRepository.UpdateAsync(mediumId, x => x.UpdateWithRequest(body)) switch { false => Result.NotFound(), true => Result.Success() }; } public async Task> PutMediumSeries(long mediumId, MediumSeriesRequest body) { return await _mediaRepository.UpdateAsync(mediumId, x => x.UpdateWithRequest(body)) switch { false => Result.NotFound(), true => Result.Success() }; } public async Task DeleteMedium(long mediumId) { await _mediaRepository.DeleteAsync(x => x.Id == mediumId); return Result.NoContent(); } #endregion #region Genres public async Task>> GetMediumGenres(long mediumId, GenreFilterQuery filterQuery, OrderQuery orderQuery, PagingQuery pagingQuery) { if (!await _mediaRepository.ExistsAsync(mediumId)) { return Result.NotFound(); } IEnumerable genres = await _mediaRepository.GetMediumGenresAsync(mediumId, filterQuery, orderQuery, pagingQuery); return Result.Success(genres.Select(x => x.ToResponse())); } public async Task PostMediumGenre(long mediumId, short genreId) { bool mediumExists = await _mediaRepository.ExistsAsync(mediumId); bool genreExists = await _genresRepository.ExistsAsync(genreId); if (mediumExists && genreExists) { await _mediaRepository.AddMediumGenreAsync(mediumId, genreId); return Result.Success(); } return Result.NotFound(); } public async Task DeleteMediumGenre(long mediumId, short genreId) { await _mediaRepository.DeleteMediumGenreAsync(mediumId, genreId); return Result.NoContent(); } #endregion #region Rating public async Task> GetMediumRating(long mediumId) { Medium? entity = await _mediaRepository.GetAsync(mediumId, x => x.Include(y => y.Ratings)); return entity switch { null => Result.NotFound(), _ => Result.Success(entity.Ratings.ToOverallResponse()) }; } public async Task> GetMediumUserRating(long mediumId, long accountId) { MediumRating? entity = await _mediaRepository.GetMediumUserRatingAsync(mediumId, accountId); return entity switch { null => Result.NotFound(), _ => Result.Success(entity.ToUserResponse()) }; } public async Task PutMediumRating(long mediumId, RatingRequest body) { Account accountEntity = await _userService.GetAccountAsync(); Medium? mediumEntity = await _mediaRepository.GetAsync(mediumId); if (mediumEntity is null) { return Result.NotFound(); } await _mediaRepository.UpdateOrAddMediumRatingAsync(mediumEntity.Id, accountEntity.Id, () => body.ToEntity(mediumEntity.Id, accountEntity.Id), x => x.UpdateWithRequest(body)); return Result.Success(); } public async Task DeleteMediumRating(long mediumId) { Account accountEntity = await _userService.GetAccountAsync(); await _mediaRepository.DeleteMediumUserRatingAsync(mediumId, accountEntity.Id); return Result.NoContent(); } #endregion #region View count public async Task PutMediumViewCount(long mediumId) { Medium? entity = await _mediaRepository.GetAsync(mediumId); if (entity is null) { return Result.NotFound(); } DateOnly date = DateOnly.FromDateTime(DateTime.UtcNow); await _mediaRepository.UpdateOrAddMediumViewCountAsync(mediumId, date, () => MediaMappers.CreateMediumViewCountEntity(mediumId), x => x.ViewCount++); return Result.Success(); } #endregion #region Pictures public async Task> GetMediumPicture(long mediumId) { MediumPicture? entity = await _mediaRepository.GetMediumPictureAsync(mediumId); return entity switch { null => Result.NotFound(), _ => Result.Success(entity.ToResponse()) }; } public async Task> PutMediumPicture(long mediumId, ImageRequest body) { return await _mediaRepository.ExistsAsync(mediumId) switch { true => Result.Success((await _mediaRepository.UpdateOrAddMediumPictureAsync(mediumId, () => body.ToEntity(mediumId), x => x.UpdateWithRequest(body))).ToResponse()), false => Result.NotFound(), }; } public async Task DeleteMediumPicture(long mediumId) { await _mediaRepository.DeleteMediumPictureAsync(mediumId); return Result.NoContent(); } #endregion #region Photos public async Task> GetMediumPhotoBackground(long mediumId) { if (!await _mediaRepository.ExistsAsync(mediumId)) { return Result.NotFound(); } Photo photo = await _photosRepository.GetPhotoRandomBackgroundByMediumAsync(mediumId, x => x.Include(y => y.Background)); return photo.ToResponse(); } #endregion #endregion #region PRIVATE METHODS private IQueryable IncludeForMediumResponse(IQueryable query, bool includePictures) where T : Medium { query = query.Include(y => y.Genres) .Include(y => y.Ratings) .Include(y => y.ViewCounts); if (includePictures) { query = query.Include(y => y.Picture); } return query; } #endregion }