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.Storage;
using FabAccessAPI;
using FabAccessAPI.Exceptions;
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;
        #endregion

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

            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;

            _ConnectionData = new ConnectionData()
            {
                Host = _ConnectionData.Host,
                Mechanism = Mechanism.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.UnbindAllEvents();
                }
            }

            try
            {
                await _API.Connect(_ConnectionData).ConfigureAwait(false);
            }
            catch (ConnectingFailedException)
            {
                Device.BeginInvokeOnMainThread(async () =>
                {
                    await _PageDialogService.DisplayAlertAsync(Resources.Text.TextResource.ALERT_ConnectionFailed, Resources.Text.TextResource.ALERT_UnableServer, Resources.Text.TextResource.OK).ConfigureAwait(false);

                    IsBusy = false;
                });
                return;
            }
            catch (AuthenticationFailedException)
            {
                Device.BeginInvokeOnMainThread(async () =>
                {
                    await _PageDialogService.DisplayAlertAsync(Resources.Text.TextResource.ALERT_ConnectionFailed, Resources.Text.TextResource.ALERT_AuthServer, Resources.Text.TextResource.OK).ConfigureAwait(false);

                    IsBusy = false;
                });
                return;
            }
            catch(Exception)
            {
                Device.BeginInvokeOnMainThread(async () =>
                {
                    await _PageDialogService.DisplayAlertAsync(Resources.Text.TextResource.ALERT_ConnectionFailed, Resources.Text.TextResource.ALERT_UnexpectedError, Resources.Text.TextResource.OK).ConfigureAwait(false);

                    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
    }
}