using BaseDomain.Results; using Microsoft.AspNetCore.Http; using Postall.Domain; using Postall.Domain.Contracts.Repositories; using Postall.Domain.Dtos; using Postall.Domain.Entities; using Postall.Domain.Services.Contracts; using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; namespace Postall.Infra.Services { public class VideoService : IVideoService { private readonly IHttpContextAccessor _httpContextAccessor; private readonly IVideoRepository _videoRepository; private readonly IChannelRepository _channelRepository; private readonly IVideoYoutubeService _videoYoutubeService; public VideoService( IHttpContextAccessor httpContextAccessor, IVideoRepository videoRepository, IChannelRepository channelRepository, IVideoYoutubeService videoYoutubeService) { _httpContextAccessor = httpContextAccessor; _videoRepository = videoRepository; _channelRepository = channelRepository; _videoYoutubeService = videoYoutubeService; } /// /// Obtém o ID do usuário atual a partir das claims /// private string GetCurrentUserId() { var user = _httpContextAccessor.HttpContext.User; var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value; if (string.IsNullOrEmpty(userId)) { var email = user.FindFirst(ClaimTypes.Email)?.Value; if (!string.IsNullOrEmpty(email)) { userId = Convert.ToBase64String( System.Text.Encoding.UTF8.GetBytes(email) ).Replace("/", "_").Replace("+", "-").Replace("=", ""); } } return userId; } /// /// Obtém todos os vídeos do usuário atual /// public async Task>> GetUserVideosAsync() { var userId = GetCurrentUserId(); if (string.IsNullOrEmpty(userId)) return new List(); var videos = await _videoRepository.GetByUserIdAsync(userId); return videos.Select(v => v.ToVideoResponse()).ToList(); } /// /// Obtém os vídeos de um canal específico para o usuário atual /// public async Task>> GetVideosByChannelIdAsync(string channelId) { if (string.IsNullOrEmpty(channelId)) return new List(); var userId = GetCurrentUserId(); if (string.IsNullOrEmpty(userId)) return new List(); var videos = await _videoRepository.GetByUserIdAndChannelIdAsync(userId, channelId); return videos.Select(v => v.ToVideoResponse()).ToList(); } /// /// Obtém os detalhes de um vídeo específico /// public async Task> GetVideoDetailsAsync(string videoId) { if (string.IsNullOrEmpty(videoId)) return Result.Failure("ID do vídeo inválido"); var videoDetails = await _videoYoutubeService.GetVideoDetailsAsync(videoId); return videoDetails; } /// /// Obtém os vídeos de um canal diretamente do YouTube /// public async Task>> GetChannelVideosFromYouTubeAsync(string channelId, int maxResults = 10) { if (string.IsNullOrEmpty(channelId)) return Result>.Failure("ID do canal inválido"); // Verifica se o canal existe para o usuário var userId = GetCurrentUserId(); var channel = await _channelRepository.GetByUserIdAndChannelIdAsync(userId, channelId); if (channel == null) return Result>.Failure("Canal não encontrado para este usuário"); // Obtém os vídeos que o usuário já adicionou para este canal var userVideos = await _videoRepository.GetByUserIdAndChannelIdAsync(userId, channelId); var userVideoIds = userVideos.Select(v => v.VideoId).ToHashSet(); // Busca os vídeos do canal no YouTube var channelVideos = await _videoYoutubeService.GetChannelVideosAsync(channelId, maxResults); if (!channelVideos.IsSuccess) return channelVideos; // Marca os vídeos que já foram adicionados pelo usuário foreach (var video in channelVideos.Value) { if (userVideoIds.Contains(video.VideoId)) { // Esse vídeo já foi adicionado pelo usuário video.Id = userVideos.First(v => v.VideoId == video.VideoId).Id; } } return channelVideos; } /// /// Adiciona um vídeo à lista do usuário /// public async Task> AddVideoAsync(string videoId, string channelId) { if (string.IsNullOrEmpty(videoId)) return Result.Failure("ID do vídeo inválido"); if (string.IsNullOrEmpty(channelId)) return Result.Failure("ID do canal inválido"); var userId = GetCurrentUserId(); if (string.IsNullOrEmpty(userId)) return Result.Failure("Usuário não identificado"); // Verifica se o canal existe para o usuário var channel = await _channelRepository.GetByUserIdAndChannelIdAsync(userId, channelId); if (channel == null) return Result.Failure("Canal não encontrado para este usuário"); // Verifica se o vídeo já existe para o usuário var existingVideo = await _videoRepository.GetByUserIdAndVideoIdAsync(userId, videoId); if (existingVideo != null) return true; // Vídeo já existe, retorna sucesso try { // Obtém os detalhes do vídeo do YouTube var videoDetails = await _videoYoutubeService.GetVideoDetailsAsync(videoId); if (!videoDetails.IsSuccess) return Result.Failure(videoDetails.Error); // Cria o objeto de dados do vídeo var videoData = new VideoData { UserId = userId, ChannelId = channelId, VideoId = videoId, Title = videoDetails.Value.Title, Description = videoDetails.Value.Description, ThumbnailUrl = videoDetails.Value.ThumbnailUrl, PublishedAt = videoDetails.Value.PublishedAt, ViewCount = videoDetails.Value.ViewCount, LikeCount = videoDetails.Value.LikeCount, DislikeCount = videoDetails.Value.DislikeCount, CommentCount = videoDetails.Value.CommentCount, CreatedAt = DateTime.UtcNow }; // Adiciona o vídeo ao repositório await _videoRepository.AddAsync(videoData); return true; } catch (Exception ex) { return Result.Failure(ex.Message); } } /// /// Adiciona múltiplos vídeos à lista do usuário /// public async Task> AddVideosAsync(List videoIds, string channelId) { if (videoIds == null || !videoIds.Any()) return Result.Failure("Lista de IDs de vídeos inválida"); if (string.IsNullOrEmpty(channelId)) return Result.Failure("ID do canal inválido"); var userId = GetCurrentUserId(); if (string.IsNullOrEmpty(userId)) return Result.Failure("Usuário não identificado"); // Verifica se o canal existe para o usuário var channel = await _channelRepository.GetByUserIdAndChannelIdAsync(userId, channelId); if (channel == null) return Result.Failure("Canal não encontrado para este usuário"); // Obtém os vídeos que o usuário já adicionou var existingVideos = await _videoRepository.GetByUserIdAsync(userId); var existingVideoIds = existingVideos.Select(v => v.VideoId).ToHashSet(); // Filtra os vídeos que ainda não foram adicionados var newVideoIds = videoIds.Where(id => !existingVideoIds.Contains(id)).ToList(); if (newVideoIds.Count == 0) return true; // Todos os vídeos já existem try { var videoDataList = new List(); // Obtém os detalhes de cada vídeo do YouTube e cria os objetos de dados foreach (var videoId in newVideoIds) { var videoDetails = await _videoYoutubeService.GetVideoDetailsAsync(videoId); if (videoDetails.IsSuccess) { videoDataList.Add(new VideoData { UserId = userId, ChannelId = channelId, VideoId = videoId, Title = videoDetails.Value.Title, Description = videoDetails.Value.Description, ThumbnailUrl = videoDetails.Value.ThumbnailUrl, PublishedAt = videoDetails.Value.PublishedAt, ViewCount = videoDetails.Value.ViewCount, LikeCount = videoDetails.Value.LikeCount, DislikeCount = videoDetails.Value.DislikeCount, CommentCount = videoDetails.Value.CommentCount, CreatedAt = DateTime.UtcNow }); } } // Adiciona os vídeos ao repositório if (videoDataList.Any()) { await _videoRepository.AddManyAsync(videoDataList); } return true; } catch (Exception ex) { return Result.Failure(ex.Message); } } /// /// Remove um vídeo da lista do usuário /// public async Task> RemoveVideoAsync(string videoId) { if (string.IsNullOrEmpty(videoId)) return Result.Failure("ID do vídeo inválido"); try { await _videoRepository.DeleteAsync(videoId); return true; } catch (Exception ex) { return Result.Failure(ex.Message); } } /// /// Busca vídeos no YouTube pelo título ou descrição /// public async Task>> SearchVideosAsync(string query, int maxResults = 10) { if (string.IsNullOrEmpty(query) || query.Length < 3) return new List(); var results = await _videoYoutubeService.SearchVideosAsync(query, maxResults); return results; } } }