using System;

namespace GraphQL.Builders
{
    /// <summary>
    /// A mutable implementation of <see cref="IResolveConnectionContext{T}"/>
    /// </summary>
    public class ResolveConnectionContext<T> : ResolveFieldContext<T>, IResolveConnectionContext<T>
    {
        private readonly int? _defaultPageSize;

        /// <summary>
        /// Initializes an instance which mirrors the specified <see cref="IResolveFieldContext"/>
        /// with the specified properties and defaults
        /// </summary>
        /// <param name="context">The underlying <see cref="IResolveFieldContext"/> to mirror</param>
        /// <param name="isUnidirectional">Indicates if the connection only allows forward paging requests</param>
        /// <param name="defaultPageSize">Indicates the default page size if not specified by the request</param>
        public ResolveConnectionContext(IResolveFieldContext context, bool isUnidirectional, int? defaultPageSize)
            : base(context)
        {
            IsUnidirectional = isUnidirectional;
            _defaultPageSize = defaultPageSize;
        }

        /// <inheritdoc/>
        public bool IsUnidirectional { get; private set; }

        /// <inheritdoc/>
        public int? First
        {
            get
            {
                var first = FirstInternal;
                if (!first.HasValue && !Last.HasValue)
                {
                    return _defaultPageSize;
                }

                return first;
            }
        }

        private int? FirstInternal
        {
            get
            {
                var first = this.GetArgument<int?>("first");
                return first.HasValue ? (int?)Math.Abs(first.Value) : null;
            }
        }

        /// <inheritdoc/>
        public int? Last
        {
            get
            {
                var last = this.GetArgument<int?>("last");
                return last.HasValue ? (int?)Math.Abs(last.Value) : null;
            }
        }

        /// <inheritdoc/>
        public string? After => this.GetArgument<string>("after");

        /// <inheritdoc/>
        public string? Before => this.GetArgument<string>("before");

        /// <inheritdoc/>
        public int? PageSize => First ?? Last ?? _defaultPageSize;
    }
}
