using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using Prism.Commands;
using Valg.Eva.Skanning.Scan.Presentation.MainWindow;
using Valg.Eva.Skanning.Scan.Presentation.RegisterBarcode;
using Valg.Eva.Skanning.Scan.Presentation.RegisterBarcode.Barcode;
using Valg.Eva.Skanning.Scan.Presentation.SelectCountingUnitPopup;
using Valg.EVA.Skanning.ContainerExtensions;
using Valg.EVA.Skanning.Contracts.CommonEnums;
using Valg.EVA.Skanning.Contracts.Security;
using Valg.EVA.Skanning.Entity.ReadModel;
using Valg.EVA.Skanning.Identity;
using Valg.EVA.Skanning.Repositories.Counting;
using Valg.EVA.Skanning.Sample.Startup.Ballot;
using Valg.EVA.Skanning.Sample.Startup.Box;
using Valg.EVA.Skanning.Scan.Presentation.Sample;
using Valg.EVA.Skanning.Services.Count;
using Valg.EVA.Skanning.ServicesModel.Internal;
using Valg.EVA.Skanning.ServicesModel.ServiceContracts.Count.Write;
using Valg.EVA.Skanning.UserInterfaceElements;
using Valg.EVA.Skanning.UserInterfaceElements.ApplicationEvents;
using Valg.EVA.Skanning.UserInterfaceElements.ApplicationTermination;
using Valg.EVA.Skanning.UserInterfaceElements.Language;
using Valg.EVA.Skanning.UserInterfaceElements.LightBox;
using Valg.EVA.Skanning.UserInterfaceElements.Login;
using Valg.EVA.Skanning.UserInterfaceElements.MessageBox;
using Valg.EVA.Skanning.UserInterfaceElements.TopBar;
using Counting = Valg.EVA.Skanning.ServicesModel.ServiceContracts.Count.Read.Counting;

namespace Valg.EVA.Skanning.Sample.Startup
{
    public class MainWindowViewModel : ViewModelBase, IMainWindowViewModel
    {
        private readonly ITypedFactory typedFactory;
        private readonly IIdentityProvider identityProvider;
        private readonly IBarcodeValidator barcodeValidator;
        private readonly ICountingService countingService;
        private readonly ICountingRepository countingRepository;

        private readonly string windowIcon = "/Valg.EVA.Skanning.Assets;component/Images/Icons/EvaVerify.ico";
        private int currentMainViewIndex;
        private const int StartPageIndex = 0;
        private const int BoxPageIndex = 1;
        private const int ChangeRolePageIndex = 2;


        public LightBoxViewModel LightBoxViewModel { get; }
        public BoxControlViewModel BoxControlViewModel { get; }
        public RegisterBarcodeViewModel RegisterBarcodeViewModel { get; }

        public DelegateCommand ShowRandomBallotCommand { get; }
        public DelegateCommand ShowRandomBoxCommand { get; }


        public MainWindowViewModel(
            ITypedFactory typedFactory,
            IIdentityProvider identityProvider,
            LightBoxViewModel lightBoxViewModel,
            BoxControlViewModel boxControlViewModel,
            RegisterBarcodeViewModel registerBarcodeViewModel,
            IBarcodeValidator barcodeValidator,
            ICountingService countingService,
            ICountingRepository countingRepository)
        {
            this.typedFactory = typedFactory;
            this.identityProvider = identityProvider;
            LightBoxViewModel = lightBoxViewModel;
            BoxControlViewModel = boxControlViewModel;
            RegisterBarcodeViewModel = registerBarcodeViewModel;
            this.barcodeValidator = barcodeValidator;
            this.countingService = countingService;
            this.countingRepository = countingRepository;

            ShowRandomBallotCommand = new DelegateCommand(ShowRandomBallot);
            ShowRandomBoxCommand = new DelegateCommand(ShowRandomBox);
        }

        protected override void SubscribeToViewModelSpecificEvents()
        {
            SubscribeToEvent<ChangeRolePageRequestedEvent, EventArgs>(ShowChangeRolePage);
            SubscribeToEvent<MainWindowRequestedEvent, EventArgs>(ShowStartPage);
            SubscribeToEvent<BarcodeCompleteEvent, BarcodeCompleteEventArgs>(BarcodeComplete);

        }
        public void Login()
        {
            var loginProcess = typedFactory.Create<LoginProcessViewModel>();
            var loginResult = loginProcess.Login(ClaimDefinitions.ScanAccessClaimType, windowIcon);

            if (loginResult != LoginResult.AccessGranted)
            {
                CloseApplication();
            }
            else
            {
                if (identityProvider.CurrentSelectedRole == null)
                {
                    ShowChangeRolePage(EventArgs.Empty);
                }
                else
                {
                    ShowBallotPage(EventArgs.Empty);
                }
            }
        }
        private void ShowBallotPage(EventArgs eventArgs)
        {
            CurrentMainViewIndex = BoxPageIndex;
        }
        private void ShowChangeRolePage(EventArgs eventArgs)
        {
            CurrentMainViewIndex = ChangeRolePageIndex;
        }

        private void ShowStartPage(EventArgs empty)
        {
            CurrentMainViewIndex = StartPageIndex;
            RegisterBarcodeViewModel.BarcodeLongText = "";
            RegisterBarcodeViewModel.ClearBarcodes();
        }
        public int CurrentMainViewIndex
        {
            get => currentMainViewIndex;
            set
            {
                currentMainViewIndex = value;
                OnPropertyChanged();
                OnPropertyChanged(PropertyHelper.GetName<MainWindowViewModel>(vm => vm.IsFooterVisible));
                if (currentMainViewIndex == StartPageIndex)
                {
                    RegisterBarcodeViewModel.SetFocusOnFirstBarcode();
                }
            }
        }
        public void CloseApplication()
        {
            PublishEvent<ApplicationTerminateRequestedEvent, EventArgs>(EventArgs.Empty);
            System.Windows.Application.Current.Shutdown();
        }

        public void ShowElectionConfigMissingWindow()
        {
        }

        public bool IsFooterVisible
        {
            get
            {
                switch (currentMainViewIndex)
                {
                    default:
                        return true;
                }
            }
        }


        private void ShowRandomBallot()
        {
            var ids = Enumerable.Range(1, 400).ToArray();
            
            CurrentMainViewIndex = BoxPageIndex;
        }
        private void ShowRandomBox()
        {
            
            BoxControlViewModel.BoxId = 2073;
            CurrentMainViewIndex = BoxPageIndex;
        }

        private void ShowSelectCountingPopup(
            string barcodeLong,
            string barcodeShort,
            IEnumerable<BoxCounting> countings)
        {
            var viewModel = new SelectCountingViewModel(MapBoxCounting(countings), s => LoadCounting(s.BoxId)); 
           var eventArgs = new LightBoxEventArgs(
                typeof(SelectCountingView),
                viewModel);

            PublishEvent<ShowLightBoxEvent, LightBoxEventArgs>(eventArgs);
        }

        private IEnumerable<CountingMetaData> MapBoxCounting(IEnumerable<BoxCounting> countings)
        {
            var result = new List<CountingMetaData>();
            foreach (var counting in countings.Where(p => p != null))
            {
                result.Add(new CountingMetaData()
                {
                    BoxId = counting.Id,
                    CountingType = counting.CountingType,
                    Counting = counting.CountNumber
                });
            }
            return result;
        }

        private void BarcodeComplete(BarcodeCompleteEventArgs eventArgs)
        {
            var validationResult = barcodeValidator.Validate(new Barcode { BarcodeLong = eventArgs.BarcodeLong, BarcodeShort = eventArgs.BarcodeShort });
            if (validationResult.IsValid)
            {
                var reportingUnits = GetReportingUnits(eventArgs);
                var wantedStates = new HashSet<BoxCountingState>(){BoxCountingState.Complete};
                
                var boxes = reportingUnits
                    .Select(ru => countingRepository.GetBoxCounting(eventArgs.BarcodeLong, eventArgs.BarcodeShort, ru.Id))
                    .Where(box => box != null && wantedStates.Contains(box.State) )
                    .ToArray();

                switch (boxes.Length)
                {
                    case 1:
                        LoadCounting(boxes.First().Id);
                        break;
                    case 0:
                        ShowWarningOrErrorsDialog(
                            EVA.Skanning.Resources.Language.SampleLanguageString.Barcode_NoBallotsFound,
                            EVA.Skanning.Resources.Language.SampleLanguageString.Barcode_NoBallotsFound_Suggestion);
                        RegisterBarcodeViewModel.ClearBarcodes();
                        RegisterBarcodeViewModel.SetFocusOnFirstBarcode();
                        break;
                    default:
                        ShowSelectCountingPopup(
                            eventArgs.BarcodeLong,
                            eventArgs.BarcodeShort, boxes);
                        break;
                }
            }
            else
            {
                ShowWarningOrErrorsDialog(
                    EVA.Skanning.Resources.Language.SampleLanguageString.Barcode_IsNotValid,
                    EVA.Skanning.Resources.Language.SampleLanguageString.Barcode_IsNotValid_Suggestion);
                RegisterBarcodeViewModel.ClearBarcodes();
                RegisterBarcodeViewModel.SetFocusOnFirstBarcode();
            }
        }


        private void LoadCounting(int boxId)
        {
            if (countingService.GetLockedBallots(boxId).LockedBallotPapers > 0)
            {
                ShowWarningOrErrorsDialog(
                    EVA.Skanning.Resources.Language.SampleLanguageString.Barcode_LockedBallotsFound,
                    EVA.Skanning.Resources.Language.SampleLanguageString.Barcode_LockedBallotsFound_Suggestion);
                RegisterBarcodeViewModel.ClearBarcodes();
                RegisterBarcodeViewModel.SetFocusOnFirstBarcode();
                return;
            }
            BoxControlViewModel.BoxId = boxId;
            CurrentMainViewIndex = BoxPageIndex;
        }

        private void ShowWarningOrErrorsDialog(string warningsOrErrorsToDisplay, params string[] suggestions)
        {
            var messageBox = typedFactory.Create<IMessageBox>();

            messageBox.Initialize(
                warningsOrErrorsToDisplay,
                string.Empty,
                suggestions,
                MessageBoxType.Warning);

            PublishEvent<ShowLightBoxEvent, LightBoxEventArgs>(new LightBoxEventArgs(messageBox as Window));
        }

        private IEnumerable<Counting> GetReportingUnits(BarcodeCompleteEventArgs eventArgs)
        {
            var electionEventId = eventArgs.BarcodeLong.GetElectionEventIdFromBarcodeLong();
            var contestId = eventArgs.BarcodeLong.GetContestIdFromBarcodeLong();
            var countingEmlAreaContextId = GetCountingEmlAreaContextId();

            return countingService.GetCountings(
                electionEventId,
                contestId,
                countingEmlAreaContextId);
        }

        private string GetCountingEmlAreaContextId()
        {
            return identityProvider.CurrentSelectedRole.CountingEmlAreaContextId;
        }
    }
}

