using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Localization;
using Moq;
using QRRapidoApp.Models.ViewModels;
using QRRapidoApp.Services;
using System.Text;
using Xunit;

namespace QRRapidoApp.Tests.Services
{
    public class QRRapidoServiceTests
    {
        private readonly Mock<IDistributedCache> _cacheMock;
        private readonly Mock<IConfiguration> _configMock;
        private readonly Mock<ILogger<QRRapidoService>> _loggerMock;
        private readonly Mock<LogoReadabilityAnalyzer> _readabilityAnalyzerMock;
        private readonly Mock<IStringLocalizer<QRRapidoApp.Resources.SharedResource>> _localizerMock;
        private readonly QRRapidoService _service;

        public QRRapidoServiceTests()
        {
            _cacheMock = new Mock<IDistributedCache>();
            _configMock = new Mock<IConfiguration>();
            _loggerMock = new Mock<ILogger<QRRapidoService>>();
            _readabilityAnalyzerMock = new Mock<LogoReadabilityAnalyzer>(Mock.Of<ILogger<LogoReadabilityAnalyzer>>(), Mock.Of<Microsoft.Extensions.Localization.IStringLocalizer<LogoReadabilityAnalyzer>>());
            _localizerMock = new Mock<IStringLocalizer<QRRapidoApp.Resources.SharedResource>>();
            
            SetupDefaultConfiguration();
            _service = new QRRapidoService(_cacheMock.Object, _configMock.Object, _loggerMock.Object, _readabilityAnalyzerMock.Object, _localizerMock.Object);
        }

        private void SetupDefaultConfiguration()
        {
            _configMock.Setup(c => c.GetValue<int>("Performance:MaxConcurrentGenerations", 100))
                      .Returns(100);
            _configMock.Setup(c => c.GetValue<int>("Performance:CacheExpirationMinutes", 60))
                      .Returns(60);
        }

        [Fact]
        public async Task GenerateRapidAsync_WithValidRequest_ShouldReturnSuccessResult()
        {
            // Arrange
            var request = new QRGenerationRequest
            {
                Type = "url",
                Content = "https://example.com",
                Size = 300,
                PrimaryColor = "#000000",
                BackgroundColor = "#FFFFFF",
                OptimizeForSpeed = true
            };

            _cacheMock.Setup(c => c.GetStringAsync(It.IsAny<string>(), default))
                     .ReturnsAsync((string)null);

            // Act
            var result = await _service.GenerateRapidAsync(request);

            // Assert
            Assert.NotNull(result);
            Assert.True(result.Success);
            Assert.False(string.IsNullOrEmpty(result.QRCodeBase64));
            Assert.False(string.IsNullOrEmpty(result.QRId));
            Assert.True(result.GenerationTimeMs > 0);
        }

        [Fact]
        public async Task GenerateRapidAsync_WithEmptyContent_ShouldReturnError()
        {
            // Arrange
            var request = new QRGenerationRequest
            {
                Type = "url",
                Content = "",
                Size = 300
            };

            // Act
            var result = await _service.GenerateRapidAsync(request);

            // Assert
            Assert.NotNull(result);
            Assert.False(result.Success);
            Assert.False(string.IsNullOrEmpty(result.ErrorMessage));
        }

        [Fact]
        public async Task GenerateRapidAsync_WithCachedResult_ShouldReturnFromCache()
        {
            // Arrange
            var request = new QRGenerationRequest
            {
                Type = "url",
                Content = "https://example.com",
                Size = 300
            };

            var cachedResult = new QRGenerationResult
            {
                QRCodeBase64 = "cached-base64",
                QRId = "cached-id",
                Success = true,
                FromCache = true
            };

            var cachedJson = System.Text.Json.JsonSerializer.Serialize(cachedResult);
            _cacheMock.Setup(c => c.GetStringAsync(It.IsAny<string>(), default))
                     .ReturnsAsync(cachedJson);

            // Act
            var result = await _service.GenerateRapidAsync(request);

            // Assert
            Assert.NotNull(result);
            Assert.True(result.Success);
            Assert.True(result.FromCache);
            Assert.Equal("cached-base64", result.QRCodeBase64);
        }

        [Fact]
        public async Task ConvertToSvgAsync_WithValidBase64_ShouldReturnSvgContent()
        {
            // Arrange
            var base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";

            // Act
            var result = await _service.ConvertToSvgAsync(base64);

            // Assert
            Assert.NotNull(result);
            var svgString = Encoding.UTF8.GetString(result);
            Assert.Contains("<?xml", svgString);
            Assert.Contains("<svg", svgString);
            Assert.Contains("</svg>", svgString);
        }

        [Fact]
        public async Task ConvertToPdfAsync_WithValidBase64_ShouldReturnPdfContent()
        {
            // Arrange
            var base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==";

            // Act
            var result = await _service.ConvertToPdfAsync(base64, 300);

            // Assert
            Assert.NotNull(result);
            var pdfString = Encoding.UTF8.GetString(result);
            Assert.Contains("%PDF", pdfString);
        }

        [Theory]
        [InlineData("url", "https://example.com")]
        [InlineData("text", "Hello World")]
        [InlineData("email", "test@example.com")]
        public async Task GenerateRapidAsync_WithDifferentTypes_ShouldHandleAllTypes(string type, string content)
        {
            // Arrange
            var request = new QRGenerationRequest
            {
                Type = type,
                Content = content,
                Size = 300,
                OptimizeForSpeed = true
            };

            _cacheMock.Setup(c => c.GetStringAsync(It.IsAny<string>(), default))
                     .ReturnsAsync((string)null);

            // Act
            var result = await _service.GenerateRapidAsync(request);

            // Assert
            Assert.NotNull(result);
            Assert.True(result.Success);
            Assert.False(string.IsNullOrEmpty(result.QRCodeBase64));
        }

        [Fact]
        public async Task GenerateRapidAsync_WithPremiumUser_ShouldUseHigherQuality()
        {
            // Arrange
            var request = new QRGenerationRequest
            {
                Type = "url",
                Content = "https://example.com",
                Size = 500,
                IsPremium = true,
                OptimizeForSpeed = true
            };

            _cacheMock.Setup(c => c.GetStringAsync(It.IsAny<string>(), default))
                     .ReturnsAsync((string)null);

            // Act
            var result = await _service.GenerateRapidAsync(request);

            // Assert
            Assert.NotNull(result);
            Assert.True(result.Success);
            Assert.True(result.Size > 0);
        }

        [Fact]
        public async Task GenerateDynamicQRAsync_WithValidData_ShouldReturnDynamicId()
        {
            // Arrange
            var request = new QRGenerationRequest
            {
                Type = "url",
                Content = "https://example.com"
            };
            var userId = "test-user-id";

            // Act
            var result = await _service.GenerateDynamicQRAsync(request, userId);

            // Assert
            Assert.False(string.IsNullOrEmpty(result));
            Assert.True(Guid.TryParse(result, out _));
        }

        [Fact]
        public async Task UpdateDynamicQRAsync_WithValidData_ShouldReturnTrue()
        {
            // Arrange
            var qrId = Guid.NewGuid().ToString();
            var newContent = "https://updated-example.com";

            // Act
            var result = await _service.UpdateDynamicQRAsync(qrId, newContent);

            // Assert
            Assert.True(result);
        }
    }
}