using Borepin.Base;
using Prism.Commands;
using Prism.Navigation;
using System.Threading.Tasks;
using System.Windows.Input;
using FabAccessAPI.Schema;
using Borepin.Model;
using Prism.Services;
using Borepin.Service;
using Borepin.Base.Exceptions;
using Capnp.Rpc;
using System;
using Borepin.ViewModel;
using System.Collections.Generic;
using NaturalSort.Extension;
using System.Linq;
using Prism.Services.Dialogs;
using Xamarin.Forms;

namespace Borepin.PageModel
{
    public class UserPageModel : ConnectionModelBase
    {
        #region Private Fields
        private string _ID;
        private User _User;
        private readonly IDialogService _DialogService;
        private bool _IsDialog;
        #endregion

        #region Contructors
        public UserPageModel(INavigationService navigationService, IPageDialogService pageDialogService, IAPIService apiService, IDialogService dialogService) : base(navigationService, pageDialogService, apiService)
        {
            _DialogService = dialogService;
            DeleteCommand = new DelegateCommand(DeleteCommandExecute);
            UpdatePasswordCommand = new DelegateCommand(UpdatePasswordCommandExecute);
        }
        #endregion

        #region Data
        public override Task LoadInstance(object instance)
        {
            if(instance is string)
            {
                _ID = instance as string;
            }
            else if(instance == null && _IsDialog)
            {

            }
            else
            {
                throw new InstanceIncorrectException();
            }

            return Task.CompletedTask;
        }

        public override async Task LoadAPIData()
        {
            if(_IsDialog)
            {
                return;
            }

            _User = (await _API.Session.UserSystem.Search.GetUserByName(_ID).ConfigureAwait(false)).Just;
            UserItem = new UserVisualize(_User);
            await UserItem.LoadData().ConfigureAwait(false);

            IReadOnlyList<Role> role_list = await _API.Session.PermissionSystem.Info.GetRoleList().ConfigureAwait(false);
            List<Role> user_role_list = new List<Role>(await _User.Info.ListRoles().ConfigureAwait(false));

            List<PermissionSelectViewModel> viewmodel_list = new List<PermissionSelectViewModel>();
            foreach (Role role in role_list)
            {
                PermissionSelectViewModel new_viewmodel = new PermissionSelectViewModel(_NavigationService, _PageDialogService, _APIService);
                object[] array = new object[]
                {
                    role,
                    _User,
                    user_role_list.Exists(x => string.Equals(x.Name, role.Name, StringComparison.Ordinal)),
                };

                await new_viewmodel.LoadInstance(array).ConfigureAwait(false);
                viewmodel_list.Add(new_viewmodel);
            }

            PermissionSelectViewModel_List = new List<PermissionSelectViewModel>(viewmodel_list.OrderBy(x => x.RoleName, StringComparison.OrdinalIgnoreCase.WithNaturalSort()));

            CanAdmin = !((UserSystem.ManageInterface_Proxy)_API.Session.UserSystem.Manage).IsNull;
            CanManage = !((User.ManageInterface_Proxy)_User.Manage).IsNull;
        }
        #endregion

        #region Fields
        private IList<PermissionSelectViewModel> _PermissionSelectViewModel_List;
        public IList<PermissionSelectViewModel> PermissionSelectViewModel_List
        {
            get => _PermissionSelectViewModel_List;
            set => SetProperty(ref _PermissionSelectViewModel_List, value);
        }

        private UserVisualize _UserItem;
        public UserVisualize UserItem
        {
            get => _UserItem;
            set => SetProperty(ref _UserItem, value);
        }

        private bool _CanAdmin;
        public bool CanAdmin
        {
            get => _CanAdmin;
            set => SetProperty(ref _CanAdmin, value);
        }

        private bool _CanManage;
        public bool CanManage
        {
            get => _CanManage;
            set => SetProperty(ref _CanManage, value);
        }

        private string _NewPassword;
        public string NewPassword
        {
            get => _NewPassword;
            set => SetProperty(ref _NewPassword, value);
        }
        #endregion

        #region Commands
        private ICommand _DeleteCommand;
        public ICommand DeleteCommand
        {
            get => _DeleteCommand;
            set => SetProperty(ref _DeleteCommand, value);
        }

        public void DeleteCommandExecute()
        {
            _IsDialog = true;

            DialogParameters parameters = new DialogParameters
            {
                { "title", Resources.Text.TextResource.DIALOG_DeleteUser },
                { "message", Resources.Text.TextResource.DIALOG_DeleteUserConfirm },
                { "instance", _User },
            };

            _DialogService.ShowDialog("ConfirmDialog", parameters, DeleteCommandExecute_Dialog);
        }

        public async void DeleteCommandExecute_Dialog(IDialogResult result)
        {
            if (string.Equals(result.Parameters.GetValue<string>("result"), "confirm", StringComparison.Ordinal))
            {
                IsBusy = true;
                if (_API.IsConnected)
                {
                    try
                    {
                        foreach(PermissionSelectViewModel viewModel in PermissionSelectViewModel_List)
                        {
                            viewModel.Dispose();
                        }

                        await _API.Session.UserSystem.Manage.RemoveUser(_User).ConfigureAwait(false);

                        Device.BeginInvokeOnMainThread(async () =>
                        {
                            INavigationResult result_nav = await _NavigationService.NavigateAsync("/MainPage/NavigationPage/UserListPage").ConfigureAwait(false);
                            if (result_nav.Exception != null)
                            {
                                Log.Fatal(result.Exception, "Navigating failed");
                            }
                        });
                    }
                    catch (RpcException exception) when (string.Equals(exception.Message, "RPC connection is broken. Task would never return.", StringComparison.Ordinal))
                    {
                        Log.Debug("RPC Connection Loss");
                    }
                }
            }
        }

        private ICommand _UpdatePasswordCommand;
        public ICommand UpdatePasswordCommand
        {
            get => _UpdatePasswordCommand;
            set => SetProperty(ref _UpdatePasswordCommand, value);
        }

        public void UpdatePasswordCommandExecute()
        {
            IsBusy = true;
            if (_API.IsConnected)
            {
                try
                {
                    _User.Admin.Pwd(NewPassword);
                    NewPassword = string.Empty;
                }
                catch (RpcException exception) when (string.Equals(exception.Message, "RPC connection is broken. Task would never return.", StringComparison.Ordinal))
                {
                    Log.Debug("RPC Connection Loss");
                }
            }
            IsBusy = false;
        }
        #endregion
    }
}
