using System.Collections.ObjectModel;
using Valg.EVA.Skanning.ContainerExtensions;
using System.Collections.Generic;
using System.Linq;

namespace Valg.EVA.Skanning.JobManagement.Startup.UI.Duplicates
{
    public class DuplicateBallotsDetailsViewModel : ReactiveViewModel
    {
        private List<BoxViewModel> boxesInvolved;
        private readonly ITypedFactory typedFactory;

        public DuplicateBallotsDetailsViewModel(ITypedFactory typedFactory)
        {
            this.typedFactory = typedFactory;
            BallotDetailsViewModels = new ObservableCollection<BallotDetailsViewModel>();
        }

        public void Initialize(List<BoxViewModel> boxes)
        {
            boxesInvolved = boxes;
            
            var viewModels = GetActiveViewModels();
            BallotDetailsViewModels.AddRange(viewModels.OrderBy(p => p.Value));
        }

        public ObservableCollection<BallotDetailsViewModel> BallotDetailsViewModels { get; }

        private IEnumerable<BallotDetailsViewModel> GetActiveViewModels()
        {
            var viewModels = new List<BallotDetailsViewModel>();
            var allDuplicates = GetAllDuplicates();
            var uniqueBallotsIds = GetUniqueBallotIds(allDuplicates);
            foreach (var ballotsIdValue in uniqueBallotsIds)
            {
                viewModels.Add(CreateBallotDetailsViewModels(ballotsIdValue, allDuplicates));
            }
            return viewModels;
        }

        private List<DuplicateBallotModel> GetAllDuplicates()
        {
            var allDuplicates = new List<DuplicateBallotModel>();
            foreach (var boxViewModel in boxesInvolved)
            {
                allDuplicates.AddRange(boxViewModel.Duplicates);
            }
            return allDuplicates;
        }

        private BallotDetailsViewModel CreateBallotDetailsViewModels(string ballotsIdValue, List<DuplicateBallotModel> allDuplicates)
        {
            var duplicates = allDuplicates.Where(p => p.Value == ballotsIdValue);
            var boxesContainingBallot = GetBoxesContainingBallot(ballotsIdValue, allDuplicates);

            var inBoxDetailsViewModel = new List<InBoxDetailsViewModel>();

            foreach (var boxId in boxesContainingBallot)
            {
                inBoxDetailsViewModel.Add(CreateInBoxDetailsViewModel(boxId, ballotsIdValue, allDuplicates));
            }
            var viewModel = typedFactory.Create<BallotDetailsViewModel>();
            viewModel.Initialize(ballotsIdValue, duplicates, inBoxDetailsViewModel);
            return viewModel;
        }

        private InBoxDetailsViewModel CreateInBoxDetailsViewModel(int boxId, string ballotsIdValue, List<DuplicateBallotModel> allDuplicates)
        {
            var duplicates = allDuplicates.Where(p => p.Value == ballotsIdValue && p.BoxCountingId == boxId);
            var box = boxesInvolved.Single(p => p.Id == boxId);
            return new InBoxDetailsViewModel(box.Name, duplicates, box.BoxNumber);
        }

        private IEnumerable<int> GetBoxesContainingBallot(string ballotsIdValue, List<DuplicateBallotModel> allDuplicates)
        {
            return allDuplicates.Where(ballotId => ballotId.Value == ballotsIdValue).Select(ballotId => ballotId.BoxCountingId).Distinct();
        }

        private IEnumerable<string> GetUniqueBallotIds(List<DuplicateBallotModel> allDuplicates)
        {
            return allDuplicates.Select(ballotId => ballotId.Value).Distinct();
        }
    }
}
