using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace InABox.Core
{
    public interface IPostResult<TPostable>
        where TPostable : IPostable
    {
        /// <summary>
        /// All successful or failed <typeparamref name="TPostable"/>s.
        /// </summary>
        public IEnumerable<TPostable> PostedEntities { get; }
        public IEnumerable<TPostable> SuccessfulEntities => PostedEntities.Where(x => x.PostedStatus == PostedStatus.Posted);
        public IEnumerable<TPostable> FailedEntities => PostedEntities.Where(x => x.PostedStatus == PostedStatus.PostFailed);

        public IEnumerable<KeyValuePair<Type, IEnumerable<IPostableFragment<TPostable>>>> Fragments { get; }
    }

    public class PostResult<TPostable> : IPostResult<TPostable>
        where TPostable : IPostable
    {
        private List<TPostable> posts = new List<TPostable>();

        private Dictionary<Type, List<IPostableFragment<TPostable>>> fragments = new Dictionary<Type, List<IPostableFragment<TPostable>>>();

        /// <summary>
        /// All successful or failed <typeparamref name="TPostable"/>s.
        /// </summary>
        public IEnumerable<TPostable> PostedEntities => posts;

        public IEnumerable<KeyValuePair<Type, IEnumerable<IPostableFragment<TPostable>>>> Fragments => 
            fragments.Select(x => new KeyValuePair<Type, IEnumerable<IPostableFragment<TPostable>>>(x.Key, x.Value));

        public void AddSuccess(TPostable post)
        {
            post.Post();
            posts.Add(post);
        }

        public void AddFailed(TPostable post, string note)
        {
            post.FailPost(note);
            posts.Add(post);
        }

        public void AddFragment(IPostableFragment<TPostable> fragment)
        {
            var type = fragment.GetType();
            if (!fragments.TryGetValue(type, out var fragmentsList))
            {
                fragmentsList = new List<IPostableFragment<TPostable>>();
                fragments[type] = fragmentsList;
            }
            fragmentsList.Add(fragment);
        }
    }
}
