// 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;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;

namespace Microsoft.AspNetCore.Internal;

public class ResponseContentTypeHelperTest
{
    public static TheoryData<MediaTypeHeaderValue, string, string> ResponseContentTypeData
    {
        get
        {
            // contentType, responseContentType, expectedContentType
            return new TheoryData<MediaTypeHeaderValue, string, string>
                {
                    // No explicit content type is provided, fall-back to the default content type
                    {
                        null,
                        null,
                        "text/default; p1=p1-value; charset=utf-8"
                    },

                    // Content type is set explicitly without encoding on action result. No charset parameter added in
                    // expected content type
                    {
                        new MediaTypeHeaderValue("text/foo"),
                        null,
                        "text/foo"
                    },

                    // Content type is set explicitly with encoding on action result. Expected content type
                    // has the charset
                    {
                        MediaTypeHeaderValue.Parse("text/foo; charset=us-ascii"),
                        null,
                        "text/foo; charset=us-ascii"
                    },

                    // Content type is set explicitly without encoding and additional parameters on action result
                    // Expected content type has the additional parameters but with no charset.
                    {
                        MediaTypeHeaderValue.Parse("text/foo; p1=p1-value"),
                        null,
                        "text/foo; p1=p1-value"
                    },

                    // Content type is set explicitly with encoding and additional parameters on action result
                    // Expected content type has the additional parameters and the charset.
                    {
                        MediaTypeHeaderValue.Parse("text/foo; p1=p1-value; charset=us-ascii"),
                        null,
                        "text/foo; p1=p1-value; charset=us-ascii"
                    },

                    // Content type is set explicitly without encoding on http response.
                    // No charset parameter added in expected content type
                    {
                        null,
                        "text/bar",
                        "text/bar"
                    },

                    // Content type is set explicitly without encoding and additional parameters on http response
                    // No charset parameter added in expected content type
                    {
                        null,
                        "text/bar; p1=p1-value",
                        "text/bar; p1=p1-value"
                    },

                    // Content type is set explicitly with encoding and additional parameters on http response
                    // Expected content type has charset and additional parameters
                    {
                        null,
                        "text/bar; p1=p1-value; charset=us-ascii",
                        "text/bar; p1=p1-value; charset=us-ascii"
                    },

                    // Content type set on action result takes precedence over the content type set on http response
                    {
                        MediaTypeHeaderValue.Parse("text/foo; charset=us-ascii"),
                        "text/bar",
                        "text/foo; charset=us-ascii"
                    },
                    {
                        MediaTypeHeaderValue.Parse("text/foo; charset=us-ascii"),
                        "text/bar; charset=utf-8",
                        "text/foo; charset=us-ascii"
                    }
                };
        }
    }

    [Theory]
    [MemberData(nameof(ResponseContentTypeData))]
    public void GetsExpectedContentTypeAndEncoding(
        MediaTypeHeaderValue contentType,
        string responseContentType,
        string expectedContentType)
    {
        // Arrange
        var defaultContentType = "text/default; p1=p1-value; charset=utf-8";

        // Act
        ResponseContentTypeHelper.ResolveContentTypeAndEncoding(
            contentType?.ToString(),
            responseContentType,
            (defaultContentType, Encoding.UTF8),
            MediaType.GetEncoding,
            out var resolvedContentType,
            out var resolvedContentTypeEncoding);

        // Assert
        Assert.Equal(expectedContentType, resolvedContentType);
    }

    [Fact]
    public void DoesNotThrowException_OnInvalidResponseContentType()
    {
        // Arrange
        var expectedContentType = "invalid-content-type";
        var defaultContentType = "text/plain; charset=utf-8";

        // Act
        ResponseContentTypeHelper.ResolveContentTypeAndEncoding(
            null,
            expectedContentType,
            (defaultContentType, Encoding.UTF8),
            MediaType.GetEncoding,
            out var resolvedContentType,
            out var resolvedContentTypeEncoding);

        // Assert
        Assert.Equal(expectedContentType, resolvedContentType);
        Assert.Equal(Encoding.UTF8, resolvedContentTypeEncoding);
    }
}
