using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NzbDrone.Api.REST;
using NzbDrone.Common.Cache;
using NzbDrone.Core.Datastore;

namespace NzbDrone.Api.Extensions
{
    public static class LazyExtensions
    {
        private static readonly ICached<MethodInfo> SetterCache = new Cached<MethodInfo>();

        public static IEnumerable<TParent> LoadSubtype<TParent, TChild>(this IEnumerable<TParent> parents, Func<TParent, int> foreignKeySelector, IBasicRepository<TChild> childRepository)
            where TChild : ModelBase, new()
            where TParent : RestResource
        {
            var parentList = parents.Where(p => foreignKeySelector(p) != 0).ToList();

            if (!parentList.Any())
            {
                return parents;
            }

            var ids = parentList.Select(foreignKeySelector).Distinct();
            var childDictionary = childRepository.Get(ids).ToDictionary(child => child.Id, child => child);

            var childSetter = GetChildSetter<TParent, TChild>();

            foreach (var episode in parentList)
            {
                childSetter.Invoke(episode, new object[] { childDictionary[foreignKeySelector(episode)] });
            }

            return parents;
        }


        private static MethodInfo GetChildSetter<TParent, TChild>()
            where TChild : ModelBase
            where TParent : RestResource
        {
            var key = typeof(TChild).FullName + typeof(TParent).FullName;

            return SetterCache.Get(key, () =>
                {
                    var property = typeof(TParent).GetProperties().Single(c => c.PropertyType == typeof(TChild));
                    return property.GetSetMethod();
                });
        }
    }
}