// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Text.Encodings.Web;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.WebEncoders.Testing;
using Xunit;

namespace Microsoft.Extensions.WebEncoders
{
    public class EncoderServiceCollectionExtensionsTests
    {
        [Fact]
        public void AddWebEncoders_WithoutOptions_RegistersDefaultEncoders()
        {
            // Arrange
            var serviceCollection = new ServiceCollection();

            // Act
            serviceCollection.AddWebEncoders();

            // Assert
            var serviceProvider = serviceCollection.BuildServiceProvider();
            Assert.Same(HtmlEncoder.Default, serviceProvider.GetRequiredService<HtmlEncoder>()); // default encoder
            Assert.Same(HtmlEncoder.Default, serviceProvider.GetRequiredService<HtmlEncoder>()); // as singleton instance
            Assert.Same(JavaScriptEncoder.Default, serviceProvider.GetRequiredService<JavaScriptEncoder>()); // default encoder
            Assert.Same(JavaScriptEncoder.Default, serviceProvider.GetRequiredService<JavaScriptEncoder>()); // as singleton instance
            Assert.Same(UrlEncoder.Default, serviceProvider.GetRequiredService<UrlEncoder>()); // default encoder
            Assert.Same(UrlEncoder.Default, serviceProvider.GetRequiredService<UrlEncoder>()); // as singleton instance
        }

        [Fact]
        public void AddWebEncoders_WithOptions_RegistersEncodersWithCustomCodeFilter()
        {
            // Arrange
            var serviceCollection = new ServiceCollection();

            // Act
            serviceCollection.AddWebEncoders(options =>
            {
                options.TextEncoderSettings = new TextEncoderSettings();
                options.TextEncoderSettings.AllowCharacters("ace".ToCharArray()); // only these three chars are allowed
            });

            // Assert
            var serviceProvider = serviceCollection.BuildServiceProvider();

            var htmlEncoder = serviceProvider.GetRequiredService<HtmlEncoder>();
            Assert.Equal("a&#x62;c&#x64;e", htmlEncoder.Encode("abcde"));
            Assert.Same(htmlEncoder, serviceProvider.GetRequiredService<HtmlEncoder>()); // as singleton instance

            var javaScriptEncoder = serviceProvider.GetRequiredService<JavaScriptEncoder>();
            Assert.Equal(@"a\u0062c\u0064e", javaScriptEncoder.Encode("abcde"));
            Assert.Same(javaScriptEncoder, serviceProvider.GetRequiredService<JavaScriptEncoder>()); // as singleton instance

            var urlEncoder = serviceProvider.GetRequiredService<UrlEncoder>();
            Assert.Equal("a%62c%64e", urlEncoder.Encode("abcde"));
            Assert.Same(urlEncoder, serviceProvider.GetRequiredService<UrlEncoder>()); // as singleton instance
        }

        [Fact]
        public void AddWebEncoders_DoesNotOverrideExistingRegisteredEncoders()
        {
            // Arrange
            var serviceCollection = new ServiceCollection();

            // Act
            serviceCollection.AddSingleton<HtmlEncoder, HtmlTestEncoder>();
            serviceCollection.AddSingleton<JavaScriptEncoder, JavaScriptTestEncoder>();
            // we don't register an existing URL encoder
            serviceCollection.AddWebEncoders(options =>
            {
                options.TextEncoderSettings = new TextEncoderSettings();
                options.TextEncoderSettings.AllowCharacters("ace".ToCharArray()); // only these three chars are allowed
            });

            // Assert
            var serviceProvider = serviceCollection.BuildServiceProvider();

            var htmlEncoder = serviceProvider.GetRequiredService<HtmlEncoder>();
            Assert.Equal("HtmlEncode[[abcde]]", htmlEncoder.Encode("abcde"));

            var javaScriptEncoder = serviceProvider.GetRequiredService<JavaScriptEncoder>();
            Assert.Equal("JavaScriptEncode[[abcde]]", javaScriptEncoder.Encode("abcde"));

            var urlEncoder = serviceProvider.GetRequiredService<UrlEncoder>();
            Assert.Equal("a%62c%64e", urlEncoder.Encode("abcde"));
        }
    }
}
