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

using System.Security.Claims;
using Microsoft.AspNetCore.Testing;

namespace Microsoft.AspNetCore.Authentication;

public class TicketSerializerTests
{
    [Fact]
    public void CanRoundTripEmptyPrincipal()
    {
        var serializer = new TicketSerializer();
        var properties = new AuthenticationProperties();
        properties.RedirectUri = "bye";
        var ticket = new AuthenticationTicket(new ClaimsPrincipal(), properties, "Hello");

        using (var stream = new MemoryStream())
        using (var writer = new BinaryWriter(stream))
        using (var reader = new BinaryReader(stream))
        {
            serializer.Write(writer, ticket);
            stream.Position = 0;
            var readTicket = serializer.Read(reader);
            Assert.Empty(readTicket.Principal.Identities);
            Assert.Equal("bye", readTicket.Properties.RedirectUri);
            Assert.Equal("Hello", readTicket.AuthenticationScheme);
        }
    }

    [Fact]
    public void CanRoundTripBootstrapContext()
    {
        var serializer = new TicketSerializer();
        var properties = new AuthenticationProperties();

        var ticket = new AuthenticationTicket(new ClaimsPrincipal(), properties, "Hello");
        ticket.Principal.AddIdentity(new ClaimsIdentity("misc") { BootstrapContext = "bootstrap" });

        using (var stream = new MemoryStream())
        using (var writer = new BinaryWriter(stream))
        using (var reader = new BinaryReader(stream))
        {
            serializer.Write(writer, ticket);
            stream.Position = 0;
            var readTicket = serializer.Read(reader);
            Assert.Single(readTicket.Principal.Identities);
            Assert.Equal("misc", readTicket.Principal.Identity.AuthenticationType);
            Assert.Equal("bootstrap", readTicket.Principal.Identities.First().BootstrapContext);
        }
    }

    [Fact]
    public void CanRoundTripActorIdentity()
    {
        var serializer = new TicketSerializer();
        var properties = new AuthenticationProperties();

        var actor = new ClaimsIdentity("actor");
        var ticket = new AuthenticationTicket(new ClaimsPrincipal(), properties, "Hello");
        ticket.Principal.AddIdentity(new ClaimsIdentity("misc") { Actor = actor });

        using (var stream = new MemoryStream())
        using (var writer = new BinaryWriter(stream))
        using (var reader = new BinaryReader(stream))
        {
            serializer.Write(writer, ticket);
            stream.Position = 0;
            var readTicket = serializer.Read(reader);
            Assert.Single(readTicket.Principal.Identities);
            Assert.Equal("misc", readTicket.Principal.Identity.AuthenticationType);

            var identity = (ClaimsIdentity)readTicket.Principal.Identity;
            Assert.NotNull(identity.Actor);
            Assert.Equal("actor", identity.Actor.AuthenticationType);
        }
    }

    [ConditionalFact]
    [FrameworkSkipCondition(
        RuntimeFrameworks.Mono,
        SkipReason = "Test fails with Mono 4.0.4. Build rarely reaches testing with Mono 4.2.1")]
    public void CanRoundTripClaimProperties()
    {
        var serializer = new TicketSerializer();
        var properties = new AuthenticationProperties();

        var claim = new Claim("type", "value", "valueType", "issuer", "original-issuer");
        claim.Properties.Add("property-1", "property-value");

        // Note: a null value MUST NOT result in a crash
        // and MUST instead be treated like an empty string.
        claim.Properties.Add("property-2", null);

        var ticket = new AuthenticationTicket(new ClaimsPrincipal(), properties, "Hello");
        ticket.Principal.AddIdentity(new ClaimsIdentity(new[] { claim }, "misc"));

        using (var stream = new MemoryStream())
        using (var writer = new BinaryWriter(stream))
        using (var reader = new BinaryReader(stream))
        {
            serializer.Write(writer, ticket);
            stream.Position = 0;
            var readTicket = serializer.Read(reader);
            Assert.Single(readTicket.Principal.Identities);
            Assert.Equal("misc", readTicket.Principal.Identity.AuthenticationType);

            var readClaim = readTicket.Principal.FindFirst("type");
            Assert.NotNull(claim);
            Assert.Equal("type", claim.Type);
            Assert.Equal("value", claim.Value);
            Assert.Equal("valueType", claim.ValueType);
            Assert.Equal("issuer", claim.Issuer);
            Assert.Equal("original-issuer", claim.OriginalIssuer);

            var property1 = readClaim.Properties["property-1"];
            Assert.Equal("property-value", property1);

            var property2 = readClaim.Properties["property-2"];
            Assert.Equal(string.Empty, property2);
        }
    }
}
