using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Input;
using Borepin.Base;
using Borepin.Base.Exceptions;
using Borepin.Service;
using Borepin.Service.ErrorMessage;
using Borepin.Service.Storage;
using FabAccessAPI;
using FabAccessAPI.Exceptions;
using FabAccessAPI.Exceptions.SASL;
using Prism.Commands;
using Prism.Navigation;
using Prism.Services;
using Xamarin.Forms;

namespace Borepin.PageModel.AddServerProcess
{
    public class AuthPlainPageModel : ConnectionModelBase
    {
        #region Private Fields
        private ConnectionData _ConnectionData;
        private readonly ILoginStorageService _LoginStorageService;
        private readonly IErrorMessageService _ErrorMessageService;
        #endregion

        #region Constructors
        public AuthPlainPageModel(INavigationService navigationService, IAPIService apiService, IPageDialogService pageDialogService, ILoginStorageService loginStorageService, IErrorMessageService errorMessageService) : base(navigationService, pageDialogService, apiService)
        {
            _LoginStorageService = loginStorageService;
            _ErrorMessageService = errorMessageService;

            AuthenticateCommand = new DelegateCommand(async () => await AuthenticateCommandExecute().ConfigureAwait(false));
        }
        #endregion

        #region LoadData
        public override Task LoadInstance(object instance)
        {
            if(instance is ConnectionData)
            {
                _ConnectionData = instance as ConnectionData;
                Username = _ConnectionData.Username;
            }
            else
            {
                throw new InstanceIncorrectException();
            }

            return Task.CompletedTask;
        }

        public override Task<object> CreateInstance()
        {
            return Task.FromResult<object>(_ConnectionData);
        }
        #endregion

        #region Fields
        private string _Username;
        public string Username
        {
            get => _Username;
            set => SetProperty(ref _Username, value);
        }

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

        #region Commands
        private ICommand _AuthenticateCommand;
        public ICommand AuthenticateCommand
        {
            get => _AuthenticateCommand;
            set => SetProperty(ref _AuthenticateCommand, value);
        }
        public async Task AuthenticateCommandExecute()
        {
            IsBusy = true;
            if(Username == null || Username == String.Empty || Password == null || Password == String.Empty)
            {
                IsBusy = false;
                return;
            }

            Username = Username.Trim();

            _ConnectionData = new ConnectionData()
            {
                Host = _ConnectionData.Host,
                Mechanism = SASLMechanismEnum.PLAIN,
                Username = Username,
                Properties = new Dictionary<string, object>(StringComparer.Ordinal)
                {
                    { "Username", Username },
                    { "Password", Password },
                },
            };

            if (_API.IsConnected)
            {
                if (_API.IsConnected)
                {
                    await _API.Disconnect().ConfigureAwait(true);
                    _API.UnbindEventHandler();
                }
            }

            try
            {
                await _API.Connect(_ConnectionData).ConfigureAwait(false);
            }
            catch (Exception exception)
            {
                _ErrorMessageService.DisplayConnectFailedMessage(exception);
                IsBusy = false;
                return;
            }

            await _LoginStorageService.Add(_ConnectionData).ConfigureAwait(false);
            await _LoginStorageService.UpdateTimestamp(_ConnectionData).ConfigureAwait(false);
            
            Device.BeginInvokeOnMainThread(async () =>
            {
                INavigationResult result = await _NavigationService.NavigateAsync("/MainPage/NavigationPage/MachineListPage").ConfigureAwait(false);
                if (result.Exception != null)
                {
                    Log.Fatal(result.Exception, "Navigating failed");
                }
            });
        }
        #endregion
    }
}