using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Packaging;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using TaskIt.Assets.Resources;
using TaskIt.Core;
using TaskIt.Infrastructure;

namespace TaskIt.ViewModels
{
    [Export]
    public class MainPageViewModel : TaskItViewModelBase, IPartImportsSatisfiedNotification
    {
        private Uri _navigateUri;

        public MainPageViewModel()
        {
            Messenger.Default.Register<OperationInProgressArgs>(this, OnOperationInProgress);
            Messenger.Default.Register<OperationCompletedArgs>(this, OnOperationCompleted);
            Messenger.Default.Register<OperationErrorArgs>(this, OnOperationError);
            Messenger.Default.Register<ErrorArgs>(this, OnError);
            Messenger.Default.Register<List<ValidationError>>(this, OnValidationErrors);
            Messenger.Default.Register<List<ValidationResult>>(this, OnValidationResults);
            Messenger.Default.Register<DeleteEntityArgs>(this, OnDeleteConfirm);
            Messenger.Default.Register<ModuleEnum>(this, OnNavigate);
            Messenger.Default.Register<NavigateToModuleArgs>(this, OnNavigateToModule);
            Messenger.Default.Register<NavigateToPageArgs>(this, OnNavigateToPage);
            Messenger.Default.Register<EntityDeletionCompletedArgs>(this, OnItemDeleted);
        }

        public void OnInstall()
        {
            try
            {
                Utils.CurrentApplication.Install(); // take the app OOB
                this.OnPropertyChanged(p => p.IsInstallCommandAvailable);
            }
            catch (Exception ex)
            {
                var errorMessage = ErrorStrings.Message_AppCannotBeInstalled + Environment.NewLine + ex.Message;
                Messenger.Default.Send(new ErrorArgs(errorMessage));
            }
        }

        public void OnCloseValidationWindow()
        {
            NotifyCloseValidationWindow();
        }

        public void OnCloseConfirmDeletionWindow()
        {
            NotifyCloseConfirmDeletionWindow();
        }

        public void OnCloseErrorWindow()
        {
            NotifyCloseErrorWindow();
        }

        public void OnOperationInProgress(OperationInProgressArgs args)
        {
            IsOperationInProgress = true;
        }

        public void OnOperationCompleted(OperationCompletedArgs args)
        {
            IsOperationInProgress = false;
        }

        public void OnOperationError(OperationErrorArgs args)
        {
            ErrorMessage = Utils.GetErrorMessage(args);
            NotifyError();
        }

        public void OnError(ErrorArgs args)
        {
            ErrorMessage = args.ErrorMessage;
            NotifyError();
        }

        public void OnValidationErrors(List<ValidationError> errors)
        {
            ValidationErrors = errors;
            NotifyValidationError();
        }

        public void OnValidationResults(List<ValidationResult> results)
        {
            ValidationResults = results;
            NotifyValidationResult();
        }

        public void OnDeleteConfirm(DeleteEntityArgs args)
        {
            EntityToDelete = args.Entity;
            NotifyConfirmDeletion();
        }

        public void OnItemDeleted(EntityDeletionCompletedArgs args)
        {
            NotifyCloseConfirmDeletionWindow();
        }

        public void OnNavigateToModule(NavigateToModuleArgs args)
        {
            OnNavigate(args.Module);
        }

        public void OnNavigateToPage(NavigateToPageArgs args)
        {
            NavigateUri = new Uri(args.PageName, UriKind.Relative);
        }

        public void OnNavigate(ModuleEnum module)
        {
            var uri = GetNavigateUri(module);
            if (GetNavigateUri(module) != null)
            {
                // The xap has already been loaded, so we can navigate to its page
                NavigateUri = uri;
                return;
            }

            // If we get here, the xap has not yet been loaded
            Utils.ShowBusyIndicator();
            switch (module)
            {
                case ModuleEnum.Tasks:
                    DownloadPackage(Constants.TASKS_XAP_FILE_NAME);
                    break;
                case ModuleEnum.Settings:
                    DownloadPackage(Constants.SETTINGS_XAP_FILE_NAME);
                    break;
                case ModuleEnum.Dashboard:
                    DownloadPackage(Constants.DASHBOARD_XAP_FILE_NAME);
                    break;
                case ModuleEnum.Help:
                    DownloadPackage(Constants.HELP_XAP_FILE_NAME);
                    break;
                default:
                    break;
            }
        }

        private Uri GetNavigateUri(ModuleEnum moduleEnum)
        {
            return (from page in Pages
                    where page.Metadata.Module == moduleEnum
                    select new Uri(page.Metadata.NavigateUri, UriKind.Relative)).FirstOrDefault();
        }

        public void OnImportsSatisfied()
        {
            if (Pages.Count <= 0)
            {
                return;
            }
            var page = Pages[Pages.Count - 1];
            NavigateUri = new Uri(page.Metadata.NavigateUri, UriKind.Relative);
        }

        private void DownloadPackage(string path)
        {
            Package.DownloadPackageAsync(new Uri(path, UriKind.Relative), LoadPackage);
        }

        public void LoadPackage(AsyncCompletedEventArgs args, Package package)
        {
            Utils.HideBusyIndicator();
            if (!args.Cancelled && args.Error == null)
            {
                Packages.AddPackage(package);
            }
        }

        # region Properties

        [Import]
        public PackageCatalog Packages { get; set; }

        [ImportMany(AllowRecomposition = true)]
        public ObservableCollection<Lazy<FrameworkElement, IPageMetadata>> Pages;

        public Uri NavigateUri
        {
            get { return _navigateUri; }
            set { _navigateUri = value; this.OnPropertyChanged(p => p.NavigateUri); }
        }

        public bool IsInstallCommandAvailable
        {
            get { return !Utils.CurrentApplication.IsRunningOutOfBrowser && Application.Current.InstallState == InstallState.NotInstalled; }
        }

        # endregion

        # region UI Events

        public event RoutedEventHandler Error;
        public void NotifyError()
        {
            if (Error != null) { Error(this, new RoutedEventArgs()); }
        }

        public event RoutedEventHandler ValidationError;
        public void NotifyValidationError()
        {
            if (ValidationError != null) { ValidationError(this, new RoutedEventArgs()); }
        }

        public event RoutedEventHandler ValidationResult;
        public void NotifyValidationResult()
        {
            if (ValidationResult != null) { ValidationResult(this, new RoutedEventArgs()); }
        }

        public event RoutedEventHandler CloseValidationWindow;
        public void NotifyCloseValidationWindow()
        {
            if (CloseValidationWindow != null) { CloseValidationWindow(this, new RoutedEventArgs()); }
        }

        public event RoutedEventHandler CloseConfirmDeletionWindow;
        public void NotifyCloseConfirmDeletionWindow()
        {
            if (CloseConfirmDeletionWindow != null) { CloseConfirmDeletionWindow(this, new RoutedEventArgs()); }
        }

        public event RoutedEventHandler CloseErrorWindow;
        public void NotifyCloseErrorWindow()
        {
            if (CloseErrorWindow != null) { CloseErrorWindow(this, new RoutedEventArgs()); }
        }

        # endregion

        # region Commands

        private RelayCommand _installCommand;
        public RelayCommand InstallCommand
        {
            get { return _installCommand ?? (_installCommand = new RelayCommand(OnInstall)); }
        }

        private RelayCommand _closeValidationWindowCommand;
        public RelayCommand CloseValidationWindowCommand
        {
            get { return _closeValidationWindowCommand ?? (_closeValidationWindowCommand = new RelayCommand(OnCloseValidationWindow)); }
        }

        private RelayCommand _closeConfirmDeletionWindowCommand;
        public RelayCommand CloseConfirmDeletionWindowCommand
        {
            get { return _closeConfirmDeletionWindowCommand ?? (_closeConfirmDeletionWindowCommand = new RelayCommand(OnCloseConfirmDeletionWindow)); }
        }

        private RelayCommand _closeErrorWindowCommand;
        public RelayCommand CloseErrorWindowCommand
        {
            get { return _closeErrorWindowCommand ?? (_closeErrorWindowCommand = new RelayCommand(OnCloseErrorWindow)); }
        }

        # endregion

        # region Resource Strings

        public string ResourceTitleError
        {
            get { return ApplicationStrings.Title_Error; }
        }

        public string ResourceTitleValidationErrors
        {
            get { return ApplicationStrings.Title_ValidationErrors; }
        }

        public string ResourceTitleConfirmDeletion
        {
            get { return ApplicationStrings.Title_ConfirmDeletion; }
        }

        public string ResourceMessagePleaseWait
        {
            get { return ApplicationStrings.Message_PleaseWait; }
        }

        public string ResourceLinkInstall
        {
            get { return ApplicationStrings.Link_Install; }
        }

        public string ResourcePageLinkHome
        {
            get { return ApplicationStrings.PageLink_Home; }
        }

        # endregion

    }
}
