using Valg.EVA.Skanning.ContainerExtensions;
using Valg.EVA.Skanning.Contracts.CommonEnums;
using Valg.EVA.Skanning.UserInterfaceElements;
using Valg.EVA.Skanning.UserInterfaceElements.Counting;
using Prism.Commands;
using ReactiveUI;
using System.Collections.Specialized;
using System.Linq;
using System.Windows.Input;
using Valg.EVA.Skanning.JobManagement.Startup.Data;
using Valg.EVA.Skanning.JobManagement.Startup.Data.Transfer;
using Valg.EVA.Skanning.JobManagement.Startup.UI.Counting;
using Valg.EVA.Skanning.JobManagement.Startup.UI.Filter;
using Valg.EVA.Skanning.JobManagement.Startup.UI.TransferOverview;

namespace Valg.EVA.Skanning.JobManagement.Startup.UI.PollingDistrict
{
    public class PollingDistrictViewModel : ReactiveViewModel, IVotingCategoryAwareViewModel, IPollingDistrictAwareViewModel
    {
        private readonly ITypedFactory typedFactory;
        private readonly IDataModel dataModel;
        private bool isChecked;
        private IReactiveDerivedList<ICountingViewModel> countings;
        private IReactiveDerivedList<TransferViewModel> transfers;

        private bool isVisible;

        public PollingDistrictViewModel(ITypedFactory typedFactory, IDataModel dataModel)
        {
            IsVisible = true;
            this.typedFactory = typedFactory;
            this.dataModel = dataModel;
            ShowDetailsCommand = new DelegateCommand(ShowDetails);
            
            this.Bubble(
                s => s.IsChecked,
                t => t.ShowPollingDistrictContent);
        }

        public string DisplayName => GetDisplayInformation();

        public VotingCategoryType ActiveVotingCategory { get; set; }

        public bool HasOnlyOnePollingDistrict { get; set; }

        public PollingDistrictModel ActivePollingDistrict { get; set; }

        public bool IsChecked
        {
            get { return isChecked; }
            set { this.RaiseAndSetIfChanged(ref isChecked, value); }
        }

        public ICommand ShowDetailsCommand { get; set; }

        public IReactiveDerivedList<ICountingViewModel> Countings
        {
            get
            {
                if (countings == null)
                {
                    LoadCountings();
                }
                return countings;
            }
        }

        public IReactiveDerivedList<TransferViewModel> Transfers
        {
            get
            {
                if (transfers == null)
                {
                    LoadTransfers();
                }
                return transfers;
            }
        }

        public bool HasActiveCounting
        {
            get
            {
                return Countings.Count(p => p.State == CountingState.Active) > 0;
            }
        }

        public bool AreAllCountingsComplete
        {
            get { return Countings.All(c => c.State == CountingState.Complete); }
        }

        public bool HasCounting => Countings.Count > 0;

        public bool NoBoxesHasBeenRegistered
        {
            get
            {
                return Countings.Any(countingViewModel => countingViewModel.BoxCountings.Count == 0);
            }
        }

        public bool ShowPollingDistrictContent => HasOnlyOnePollingDistrict || IsChecked;
        public bool IsVisible
        {
            get { return isVisible; }
            set
            {
                isVisible = value;
                OnPropertyChanged();
            }
        }

        protected override void SubscribeToViewModelSpecificEvents()
        {
            SubscribeToEvent<FilterChangedEvent, FilterChangedEventArgs>(FilterHasChangedHandler);
        }

        private void FilterHasChangedHandler(FilterChangedEventArgs eventArgs)
        {
            if (eventArgs.ActiveVotingCategory == ActiveVotingCategory)
            {
                IsVisible = !ShouldHide(eventArgs.Filter);
            }
        }

        private bool ShouldHide(string filter)
        {
            string[] filterParts = filter.ToUpperInvariant().Split(' ');
            var description = DisplayName.ToUpperInvariant();

            return filterParts.Any(part => !string.IsNullOrWhiteSpace(part) && !description.Contains(part));
        }

        private void LoadCountings()
        {
            if (countings != null)
            {
                countings.CollectionChanged -= Countings_CollectionChanged;
            }

            countings = CreateDerivedCountings();

            IsChecked = !AreAllCountingsComplete;

            countings.BubbleCollection(
                this,
                t => t.HasActiveCounting,
                t => t.HasCounting,
                t => t.DisplayName,
                t => t.AreAllCountingsComplete);

            countings.CollectionChanged += Countings_CollectionChanged;
        }

        private void LoadTransfers()
        {
            transfers = CreateDerivedTransfers();

            transfers.BubbleCollection(
                this,
                t => t.DisplayName);

        }
        private IReactiveDerivedList<TransferViewModel> CreateDerivedTransfers()
        {
            var votingCategory = ActiveVotingCategory.Key();

            return dataModel.CompletedCountings.CreateDerivedCollection(
                CreateTransferViewModel,
                vm => vm.Counting.EmlAreaContextId == ActivePollingDistrict.Id && vm.Counting.VotingCategory == votingCategory);
        }

        private IReactiveDerivedList<ICountingViewModel> CreateDerivedCountings()
        {
            var votingCategory = ActiveVotingCategory.Key();
            var derivedCountings = dataModel.Countings.CreateDerivedCollection(
                CreateCountingViewModel,
                c => c.EmlAreaContextId == ActivePollingDistrict.Id && c.VotingCategory == votingCategory);
            return derivedCountings;
        }

        private void ShowDetails()
        {
            IsChecked = !IsChecked;
        }

        private string GetDisplayInformation()
        {
            var districtCodeAndName = $"{GetPollingDistrictCode(ActivePollingDistrict.Id)} - {ActivePollingDistrict.Name}";
            var displayInformation = districtCodeAndName;

            if (NoBoxesHasBeenRegistered)
            {
                displayInformation += " - " + Resources.Language.LanguageString.Counting_WaitingForFirstRegisteredBox;
            }
            else if (HasActiveCounting)
            {
                var counting = Countings.Last();
                if (counting.IsCompleteCountingButtonEnabled)
                {
                    displayInformation += " - " + Resources.Language.JobManagementLanguageString.CountingStatus_ReadyForCompletion;
                }
                else
                {
                    displayInformation += " - " + counting.Model.CountingType.GetCountingDescription(counting.Model.CountNumber) + " " + Resources.Language.JobManagementLanguageString.PollingDistrictTitle_ActiveSuffix;
                }
            }
            else
            {
                displayInformation += " - "  + Resources.Language.JobManagementLanguageString.CountingStatus_Start;
            }


            if (Transfers.Any())
            {
                var transfer = Transfers.Last();
                if (transfer.State.Equals(TransferState.NotStarted))
                {
                    displayInformation += " - " + Resources.Language.JobManagementLanguageString.CountingStatus_ReadyForTransfer;
                }
                else if (transfer.State.Equals(TransferState.FinishedOnServer))
                {
                    displayInformation += " - " + Resources.Language.JobManagementLanguageString.CountingStatus_Transferred;
                }
                else if (transfer.State.Equals(TransferState.ErrorOnServer))
                {
                    displayInformation += " - " + Resources.Language.JobManagementLanguageString.CountingStatus_TransferFailed;
                }
            }

            return displayInformation;
        }

        private string GetPollingDistrictCode(string pollingDistrictId)
        {
            var parts = pollingDistrictId.Split('.');
            return parts.LastOrDefault();
        }

        private void Countings_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == NotifyCollectionChangedAction.Add)
            {
                if (Countings.Any(c => !c.BoxCountings.Any()))
                {
                    IsChecked = true;
                }
            }
        }

        private TransferViewModel CreateTransferViewModel(CountingCompleteModel model)
        {
            var viewModel = typedFactory.Create<TransferViewModel>();
            viewModel.Initialize(model);

            viewModel.Bubble(
                s => s.State,
                this,
                t => t.DisplayName);

            return viewModel;
        }
        private ICountingViewModel CreateCountingViewModel(CountingModel model)
        {
            var viewModel = typedFactory.Create<ICountingViewModel>();
            viewModel.SetModel(model);
            viewModel.Bubble(
                s => s.State,
                this,
                t => t.HasActiveCounting,
                t => t.DisplayName,
                t => t.AreAllCountingsComplete);
            viewModel.Bubble(
                s => s.IsCompleteCountingButtonEnabled,
                this,
                vm => vm.DisplayName);

            return viewModel;
        }
    }
}
