using Microsoft.Extensions.Logging; using SumaTube.Application.Videos.Contracts; using SumaTube.Domain.Entities.Videos; using SumaTube.Infra.Contracts.Repositories.Videos; using SumaTube.Infra.VideoSumarizer.Contracts; using SumaTube.Infra.VideoSumarizer.Videos; namespace SumaTube.Application.Videos.ApplicationServices { public class VideoApplicationService : IVideoApplicationService { private readonly IVideoSummaryRepository _repository; private readonly IVideoSumarizerService _sumarizerService; private readonly ILogger _logger; public VideoApplicationService( IVideoSummaryRepository repository, IVideoSumarizerService sumarizerService, ILogger logger) { _repository = repository; _sumarizerService = sumarizerService; _logger = logger; } public async Task> GetUserVideosAsync(string userId) { _logger.LogInformation("Obtendo videos do usuário: {UserId}", userId); return await _repository.GetByUserIdAsync(userId); } public async Task GetVideoSummaryByIdAsync(string id, string userId) { _logger.LogInformation("Obtendo resumo com ID: {SummaryId} para usuário: {UserId}", id, userId); var summary = await _repository.GetByIdAsync(id); if (summary == null || summary.UserId != userId) { _logger.LogWarning("Resumo não encontrado ou acesso não autorizado. ID: {SummaryId}, UserId: {UserId}", id, userId); return null; } return summary; } public async Task RequestVideoSummaryAsync(string youtubeUrl, string language, string userId) { _logger.LogInformation("Solicitando resumo para URL: {Url}, idioma: {Language}, usuário: {UserId}", youtubeUrl, language, userId); try { // Extrair ID do vídeo string videoId = ExtractVideoId(youtubeUrl); if (string.IsNullOrEmpty(videoId)) { _logger.LogWarning("URL do YouTube inválida: {Url}", youtubeUrl); throw new ArgumentException("URL do YouTube inválida"); } // Verificar se já existe um resumo para este vídeo/usuário/idioma bool exists = await _repository.ExistsAsync(videoId, userId, language); if (exists) { _logger.LogInformation("Resumo já existente para vídeo: {VideoId}, usuário: {UserId}, idioma: {Language}", videoId, userId, language); return await _repository.GetByVideoIdAndUserIdAndLanguageAsync(videoId, userId, language); } // Criar novo resumo var sessionId = Guid.NewGuid().ToString(); var summary = VideoSummary.Create(videoId, userId, language, sessionId); // Salvar no repositório await _repository.AddAsync(summary); // Enviar para processamento via RabbitMQ _logger.LogInformation("Enviando solicitação para processamento. SessionId: {SessionId}", sessionId); await _sumarizerService.RequestVideoSummarization(sessionId, youtubeUrl, language); return summary; } catch (Exception ex) { _logger.LogError(ex, "Erro ao solicitar resumo de vídeo: {Message}", ex.Message); throw; } } public async Task CheckSummaryStatusAsync(string id, string userId) { _logger.LogInformation("Verificando status do resumo. ID: {SummaryId}, usuário: {UserId}", id, userId); var summary = await _repository.GetByIdAsync(id); if (summary == null || summary.UserId != userId) { _logger.LogWarning("Resumo não encontrado ou acesso não autorizado. ID: {SummaryId}, UserId: {UserId}", id, userId); return new { status = "NOT_FOUND" }; } return new { status = summary.Status, title = summary.Title, thumbnailUrl = summary.ThumbnailUrl, errorMessage = summary.ErrorMessage }; } private string ExtractVideoId(string url) { try { var uri = new Uri(url); if (uri.Host.Contains("youtube.com")) { var query = System.Web.HttpUtility.ParseQueryString(uri.Query); return query["v"]; } else if (uri.Host.Contains("youtu.be")) { var segments = uri.Segments; return segments[segments.Length - 1].TrimEnd('/'); } } catch (Exception ex) { _logger.LogError(ex, "Erro ao extrair ID do vídeo da URL: {Url}", url); } return null; } } }