using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Timeline.Services.User
{
    /// 
    /// Represents a user's permissions.
    /// 
    public class UserPermissions : IEnumerable, IEquatable
    {
        public static UserPermissions AllPermissions { get; } = new UserPermissions(Enum.GetValues());
        /// 
        /// Create an instance containing given permissions.
        /// 
        /// Permission list.
        public UserPermissions(params UserPermission[] permissions) : this(permissions as IEnumerable)
        {
        }
        /// 
        /// Create an instance containing given permissions.
        /// 
        /// Permission list.
        /// Thrown when  is null.
        public UserPermissions(IEnumerable permissions)
        {
            if (permissions == null) throw new ArgumentNullException(nameof(permissions));
            _permissions = new SortedSet(permissions);
        }
        private readonly SortedSet _permissions = new();
        /// 
        /// Check if a permission is contained in the list.
        /// 
        /// The permission to check.
        /// True if contains. Otherwise false.
        public bool Contains(UserPermission permission)
        {
            return _permissions.Contains(permission);
        }
        /// 
        /// To a serializable string list.
        /// 
        /// A string list.
        public List ToStringList()
        {
            return _permissions.Select(p => p.ToString()).ToList();
        }
        /// 
        /// Convert a string list to user permissions.
        /// 
        /// The string list.
        /// An instance.
        /// Thrown when  is null.
        /// Thrown when there is unknown permission name.
        public static UserPermissions FromStringList(IEnumerable list)
        {
            List permissions = new();
            foreach (var value in list)
            {
                if (Enum.TryParse(value, false, out var result))
                {
                    permissions.Add(result);
                }
                else
                {
                    throw new ArgumentException("Unknown permission name.", nameof(list));
                }
            }
            return new UserPermissions(permissions);
        }
        public IEnumerator GetEnumerator()
        {
            return _permissions.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable)_permissions).GetEnumerator();
        }
        public bool Equals(UserPermissions? other)
        {
            if (other == null)
                return false;
            return _permissions.SequenceEqual(other._permissions);
        }
        public override bool Equals(object? obj)
        {
            return Equals(obj as UserPermissions);
        }
        public override int GetHashCode()
        {
            int result = 0;
            foreach (var permission in Enum.GetValues())
            {
                if (_permissions.Contains(permission))
                {
                    result += 1;
                }
                result <<= 1;
            }
            return result;
        }
    }
}