using Borepin.Base;
using Borepin.Service.ErrorMessage;
using FabAccessAPI;
using FabAccessAPI.Exceptions;
using Prism.Commands;
using Prism.Navigation;
using Prism.Services;
using System;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;

namespace Borepin.PageModel.AddServerProcess
{
    public class SelectServerPageModel : PageModelBase
    {
        #region Private Fields
        private ConnectionData _ConnectionData;
        private IErrorMessageService _ErrorMessageService;
        #endregion

        #region Constructors
        public SelectServerPageModel(INavigationService navigationService, IPageDialogService pageDialogService, IErrorMessageService errorMessageService) : base(navigationService, pageDialogService)
        {
            _ErrorMessageService = errorMessageService;

            ConnectToServerCommand = new DelegateCommand(async () => await ConnectToServerExecute().ConfigureAwait(false));
            DetectLocalServerCommand = new DelegateCommand(DetectHostCommandExecute);
            ScanCodeCommand = new DelegateCommand(ScanCodeCommandExecute);
        }
        #endregion

        #region LoadData
        public override Task LoadInstance(object instance)
        {
            if(instance is ConnectionData)
            {
                _ConnectionData = instance as ConnectionData;
                Host = _ConnectionData.Host.ToString();
            }

            return Task.CompletedTask;
        }

        public override Task LoadFromParameters(INavigationParameters parameters)
        {
            if(parameters.ContainsKey("result") && string.Equals((string)parameters["result"], "scanned", StringComparison.Ordinal) && parameters.ContainsKey("value"))
            {
                Host = (string)parameters["value"];
            }

            return Task.CompletedTask;
        }

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

        #region Fields
        private string _Host;
        public string Host
        {
            get => _Host;
            set => SetProperty(ref _Host, value);
        }
        #endregion

        #region Commands
        private ICommand _ConnectToServerCommand;
        public ICommand ConnectToServerCommand
        {
            get => _ConnectToServerCommand;
            set => SetProperty(ref _ConnectToServerCommand, value);
        }
        public async Task ConnectToServerExecute()
        {
            if (Host == "" || Host == null)
            {
                return;
            }

            IsBusy = true;

            try
            {
                string server_address = "";
                if(Regex.IsMatch(Host, "([a-zA-Z]{2,20}):\\/\\/", RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture, TimeSpan.FromSeconds(1)))
                {
                    server_address = Host;
                }
                else
                {
                    server_address = "http://" + Host;
                }
                
                UriBuilder builder = new UriBuilder(server_address);
                if (builder.Port == 80)
                {
                    builder.Port = 59661;
                }

                _ConnectionData = new ConnectionData()
                {
                    Host = builder.Uri,
                };
            }
            catch (UriFormatException)
            {
                Device.BeginInvokeOnMainThread(async () =>
                {
                    await _PageDialogService.DisplayAlertAsync(Resources.Text.TextResource.ALERT_ConnectionFailed, Resources.Text.TextResource.ALERT_AddressInvalid, Resources.Text.TextResource.OK).ConfigureAwait(false);

                    IsBusy = false;
                });

                return;
            }

            try
            {
                API api = new API();
                await api.TryToConnect(_ConnectionData).ConfigureAwait(false);
            }
            catch(Exception exception)
            {
                _ErrorMessageService.DisplayConnectFailedMessage(exception);
                IsBusy = false;
                return;
            }

            Device.BeginInvokeOnMainThread(async () =>
            {
                INavigationResult result = await _NavigationService.NavigateAsync("AddServerProcess_ChooseAuthTypePage").ConfigureAwait(false);
                if (result.Exception != null)
                {
                    Log.Fatal(result.Exception, "Navigating failed");
                }
            });
        }

        private ICommand _ScanCodeCommand;
        public ICommand ScanCodeCommand
        {
            get => _ScanCodeCommand;
            set => SetProperty(ref _ScanCodeCommand, value);
        }
        public void ScanCodeCommandExecute()
        {
            Device.BeginInvokeOnMainThread(async () =>
            {
                INavigationResult result = await _NavigationService.NavigateAsync("ScanPage").ConfigureAwait(false);
                if (result.Exception != null)
                {
                    Log.Fatal(result.Exception, "Navigating failed");
                }
            });
        }

        private ICommand _DetectLocalServerCommand;
        public ICommand DetectLocalServerCommand
        {
            get => _DetectLocalServerCommand;
            set => SetProperty(ref _DetectLocalServerCommand, value);
        }
        public void DetectHostCommandExecute()
        {
            // Get Example Server Address
            Host = "127.0.0.1:59661";
        }
        #endregion
    }
}
