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

namespace Quadarax.Foundation.Core.Data.Diff
{
    public class DiffComparator<TEntry> where TEntry : DiffEntry, new()
    {
        private readonly IEnumerable<TEntry> _left;
        private readonly IEnumerable<TEntry> _right;

        public DiffComparator(IEnumerable<TEntry> leftCollection, IEnumerable<TEntry> rightCollection)
        {
            _left = leftCollection;
            _right = rightCollection;
        }

        public DiffComparator(IEnumerable<object> leftData, IEnumerable<object> rightData)
        {
            var left = new List<TEntry>();
            foreach (var data in leftData)
            {
                var entry = new TEntry();
                entry.SetItem(data);
                left.Add(entry);
            }

            _left = left;

            var right = new List<TEntry>();
            foreach (var data in rightData)
            {
                var entry = new TEntry();
                entry.SetItem(data);
                right.Add(entry);
            }
            _right = right;
        }

        public IEnumerable<TEntry> CompareLeftSide()
        {
            return _left.Select(letItem => Compare(letItem, _right)).ToList();
        }

        public IEnumerable<TEntry> CompareRightSide()
        {
            return _right.Select(rightItem => Compare(rightItem, _left)).ToList();
        }

        private TEntry Compare(TEntry source, IEnumerable<TEntry> target)
        {
            if (source == null)
                throw new ArgumentNullException(nameof(source));
            if (target == null)
                throw new ArgumentNullException(nameof(target));

            var key = source.GetKey();
            source.SetCompareState(source.Compare(Find(key, target)));
            return source;
        }

        private TEntry? Find(object key, IEnumerable<TEntry> target)
        {
            if (target == null)
                throw new ArgumentNullException(nameof(target));

            return target.FirstOrDefault(x => Equals(x.GetKey(), key));
        }
    }
}
