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

using Microsoft.Net.Http.Headers;

namespace Microsoft.AspNetCore.Http;

/// <summary>
/// Options used to create a new cookie.
/// </summary>
public class CookieOptions
{
    private List<string>? _extensions;

    /// <summary>
    /// Creates a default cookie with a path of '/'.
    /// </summary>
    public CookieOptions()
    {
        Path = "/";
    }

    /// <summary>
    /// Creates a copy of the given <see cref="CookieOptions"/>.
    /// </summary>
    public CookieOptions(CookieOptions options)
    {
        ArgumentNullException.ThrowIfNull(options);

        Domain = options.Domain;
        Path = options.Path;
        Expires = options.Expires;
        Secure = options.Secure;
        SameSite = options.SameSite;
        HttpOnly = options.HttpOnly;
        MaxAge = options.MaxAge;
        IsEssential = options.IsEssential;

        if (options._extensions?.Count > 0)
        {
            _extensions = new List<string>(options._extensions);
        }
    }

    /// <summary>
    /// Gets or sets the domain to associate the cookie with.
    /// </summary>
    /// <returns>The domain to associate the cookie with.</returns>
    public string? Domain { get; set; }

    /// <summary>
    /// Gets or sets the cookie path.
    /// </summary>
    /// <returns>The cookie path.</returns>
    public string? Path { get; set; }

    /// <summary>
    /// Gets or sets the expiration date and time for the cookie.
    /// </summary>
    /// <returns>The expiration date and time for the cookie.</returns>
    public DateTimeOffset? Expires { get; set; }

    /// <summary>
    /// Gets or sets a value that indicates whether to transmit the cookie using Secure Sockets Layer (SSL)--that is, over HTTPS only.
    /// </summary>
    /// <returns>true to transmit the cookie only over an SSL connection (HTTPS); otherwise, false.</returns>
    public bool Secure { get; set; }

    /// <summary>
    /// Gets or sets the value for the SameSite attribute of the cookie. The default value is <see cref="SameSiteMode.Unspecified"/>
    /// </summary>
    /// <returns>The <see cref="SameSiteMode"/> representing the enforcement mode of the cookie.</returns>
    public SameSiteMode SameSite { get; set; } = SameSiteMode.Unspecified;

    /// <summary>
    /// Gets or sets a value that indicates whether a cookie is inaccessible by client-side script.
    /// </summary>
    /// <returns>true if a cookie must not be accessible by client-side script; otherwise, false.</returns>
    public bool HttpOnly { get; set; }

    /// <summary>
    /// Gets or sets the max-age for the cookie.
    /// </summary>
    /// <returns>The max-age date and time for the cookie.</returns>
    public TimeSpan? MaxAge { get; set; }

    /// <summary>
    /// Indicates if this cookie is essential for the application to function correctly. If true then
    /// consent policy checks may be bypassed. The default value is false.
    /// </summary>
    public bool IsEssential { get; set; }

    /// <summary>
    /// Gets a collection of additional values to append to the cookie.
    /// </summary>
    public IList<string> Extensions
    {
        get => _extensions ??= new List<string>();
    }

    /// <summary>
    /// Creates a <see cref="SetCookieHeaderValue"/> using the current options.
    /// </summary>
    public SetCookieHeaderValue CreateCookieHeader(string name, string value)
    {
        var cookie = new SetCookieHeaderValue(name, value)
        {
            Domain = Domain,
            Path = Path,
            Expires = Expires,
            Secure = Secure,
            HttpOnly = HttpOnly,
            MaxAge = MaxAge,
            SameSite = (Net.Http.Headers.SameSiteMode)SameSite,
        };

        if (_extensions?.Count > 0)
        {
            foreach (var extension in _extensions)
            {
                cookie.Extensions.Add(extension);
            }
        }

        return cookie;
    }
}
