using Google.Apis.Services;
using Google.Apis.YouTube.v3;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Postall.Domain.Services.Contracts;
using Postall.Infra.Dtos;
using System.Security.Claims;

namespace Postall.Infra.Services
{
    public class YouTubeServiceVideo: IVideoService
    {
        private readonly IConfiguration _configuration;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly string _apiKey;
        private readonly string _clientId;
        private readonly string _clientSecret;

        public YouTubeServiceVideo(IConfiguration configuration, IHttpContextAccessor httpContextAccessor)
        {
            _configuration = configuration;
            _httpContextAccessor = httpContextAccessor;

            _apiKey = _configuration["YouTube:ApiKey"];
            _clientId = _configuration["Authentication:Google:ClientId"];
            _clientSecret = _configuration["Authentication:Google:ClientSecret"];
        }

        /// <summary>
        /// Obtém o ID do usuário atual a partir das claims
        /// </summary>
        private string GetCurrentUserId()
        {
            var user = _httpContextAccessor.HttpContext.User;

            // Primeiro tentar obter o NameIdentifier (que foi adicionado no ExternalLoginCallback)
            var userId = user.FindFirst(ClaimTypes.NameIdentifier)?.Value;

            // Se não encontrou, tenta usar o email como identificador
            if (string.IsNullOrEmpty(userId))
            {
                var email = user.FindFirst(ClaimTypes.Email)?.Value;
                if (!string.IsNullOrEmpty(email))
                {
                    // Gerar ID baseado no email (mesmo método usado no ExternalLoginCallback)
                    userId = Convert.ToBase64String(
                        System.Text.Encoding.UTF8.GetBytes(email)
                    ).Replace("/", "_").Replace("+", "-").Replace("=", "");
                }
            }

            return userId;
        }

        /// <summary>
        /// Obtém os vídeos dos canais que o usuário tem acesso, ordenados por data
        /// </summary>
        public async Task<List<VideoItemResponse>> GetUserChannelVideosAsync(int maxResults = 10)
        {
            // Obter o ID do usuário das claims
            var userId = GetCurrentUserId();

            if (string.IsNullOrEmpty(userId))
                return new List<VideoItemResponse>();

            // Obter os canais do usuário do banco de dados
            var userChannels = await GetUserChannelsAsync(userId);

            if (!userChannels.Any())
                return new List<VideoItemResponse>();

            var videos = new List<VideoItemResponse>();

            // Para cada canal, buscar os vídeos recentes
            foreach (var channelId in userChannels)
            {
                var channelVideos = await GetChannelVideosAsync(channelId, maxResults);
                videos.AddRange(channelVideos);
            }

            // Ordenar por data de publicação e pegar os mais recentes
            return videos
                .OrderByDescending(v => v.PublishedAt)
                .Take(maxResults)
                .ToList();
        }

        /// <summary>
        /// Obtém os vídeos de um canal específico
        /// </summary>
        public async Task<List<VideoItemResponse>> GetChannelVideosAsync(string channelId, int maxResults = 10)
        {
            try
            {
                var youtubeService = new YouTubeBaseServiceWrapper(_apiKey);

                // Primeiro, buscar os IDs dos últimos vídeos do canal
                var searchRequest = youtubeService.Search.List("snippet");
                searchRequest.ChannelId = channelId;
                searchRequest.Order = SearchResource.ListRequest.OrderEnum.Date;
                searchRequest.MaxResults = maxResults;
                searchRequest.Type = "video";

                var searchResponse = await searchRequest.ExecuteAsync();

                if (searchResponse.Items == null || searchResponse.Items.Count == 0)
                    return new List<VideoItemResponse>();

                // Obter os IDs dos vídeos
                var videoIds = searchResponse.Items.Select(i => i.Id.VideoId).ToList();

                // Buscar detalhes dos vídeos
                var videosRequest = youtubeService.Videos.List("snippet,contentDetails,statistics");
                videosRequest.Id = string.Join(",", videoIds);
                var videosResponse = await videosRequest.ExecuteAsync();

                // Converter para o modelo
                var videos = new List<VideoItemResponse>();
                foreach (var videoItem in videosResponse.Items)
                {
                    var searchItem = searchResponse.Items.FirstOrDefault(i => i.Id.VideoId == videoItem.Id);

                    videos.Add(new VideoItemResponse
                    {
                        Id = videoItem.Id,
                        Title = videoItem.Snippet.Title,
                        Description = videoItem.Snippet.Description,
                        ThumbnailUrl = videoItem.Snippet.Thumbnails.High.Url,
                        PublishedAt = videoItem.Snippet.PublishedAt.Value,
                        ChannelId = videoItem.Snippet.ChannelId,
                        ChannelTitle = videoItem.Snippet.ChannelTitle
                    });
                }

                return videos;
            }
            catch (Exception ex)
            {
                // Em produção, use um logger adequado
                Console.WriteLine($"Erro ao obter vídeos do canal {channelId}: {ex.Message}");
                return new List<VideoItemResponse>();
            }
        }

        /// <summary>
        /// Método para buscar os canais que o usuário gerencia ou tem acesso
        /// Em um cenário real, isso viria do banco de dados
        /// </summary>
        private async Task<List<string>> GetUserChannelsAsync(string userId)
        {
            // TODO: Substituir isso por uma consulta real ao banco de dados

            // Em produção, você deve implementar uma tabela que relacione 
            // os usuários com seus canais do YouTube

            // Para teste, aqui estão alguns canais populares
            // Na implementação real, você deve armazenar os canais que o usuário tem permissão
            return new List<string>
            {
                "UC_x5XG1OV2P6uZZ5FSM9Ttw", // Google Developers
                "UCt84aUC9OG6di8kSdKzEHTQ", // Outro canal de exemplo
                "UCkw4JCwteGrDHIsyIIKo4tQ"  // Google
            };
        }

        /// <summary>
        /// Salva um vídeo para o usuário atual
        /// Em produção, isso salvaria no banco de dados
        /// </summary>
        public async Task SaveVideoForUserAsync(string videoId)
        {
            var userId = GetCurrentUserId();

            if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(videoId))
                return;

            // TODO: Salvar no banco de dados a relação entre o usuário e o vídeo

            // Código de exemplo:
            // await _dbContext.UserVideos.AddAsync(new UserVideo
            // {
            //     UserId = userId,
            //     VideoId = videoId,
            //     DateAdded = DateTime.UtcNow
            // });
            // await _dbContext.SaveChangesAsync();
        }

        /// <summary>
        /// Remove um vídeo do usuário atual
        /// Em produção, isso removeria do banco de dados
        /// </summary>
        public async Task RemoveVideoForUserAsync(string videoId)
        {
            var userId = GetCurrentUserId();

            if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(videoId))
                return;

            // TODO: Remover do banco de dados a relação entre o usuário e o vídeo

            // Código de exemplo:
            // var userVideo = await _dbContext.UserVideos
            //     .FirstOrDefaultAsync(uv => uv.UserId == userId && uv.VideoId == videoId);
            // if (userVideo != null)
            // {
            //     _dbContext.UserVideos.Remove(userVideo);
            //     await _dbContext.SaveChangesAsync();
            // }
        }
    }

    /// <summary>
    /// Wrapper para o serviço base do YouTube
    /// </summary>
    public class YouTubeBaseServiceWrapper : YouTubeService
    {
        public YouTubeBaseServiceWrapper(string apiKey)
            : base(new BaseClientService.Initializer()
            {
                ApiKey = apiKey,
                ApplicationName = "PostAll"
            })
        {
        }
    }
}
