using System;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;

using Xamarin.Forms;

using RestSharp;
using Plugin.Permissions;
using Plugin.Permissions.Abstractions;

using Syncfusion.Licensing;
using comal.timesheets;
using Xamarin.Essentials;
using PermissionStatus = Plugin.Permissions.Abstractions.PermissionStatus;
using InABox.Core;
using InABox.Clients;
using InABox.Configuration;

namespace InABox.Mobile
{

    public enum PermissionType
    {

        Unknown,
        Calendar,
        Camera,
        Contacts,
        Location,
        Microphone,
        Phone,
        Photos,
        Reminders,
        Sensors,
        Sms,
        Storage,
        Speech,
        LocationAlways,
        LocationWhenInUse,
        MediaLibrary
    }



    public static class MobileUtils
    {

        public static void Init()
        {
            Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense(InABox.Core.CoreUtils.SyncfusionLicense(Core.SyncfusionVersion.v20_3));
        }

        public static String GetDeviceID()
        {
            IDeviceID deviceID = DependencyService.Get<IDeviceID>();
            return deviceID.DeviceID();
        }

        public static IAppVersion AppVersion { get { return DependencyService.Get<IAppVersion>(); } }

        public static void SaveToSecureStorage()
        {
            try
            {
                SecureStorage.SetAsync(GlobalVariables.CacheURLString, App.Settings.URL);
                SecureStorage.SetAsync(GlobalVariables.CachePortString, App.Settings.Port.ToString());
                SecureStorage.SetAsync(GlobalVariables.CacheUserIDString, App.Settings.UserID);
                SecureStorage.SetAsync(GlobalVariables.CachePasswordString, App.Settings.Password);
            }
            catch { }
        }

        public static void LoadFromLink()
        {
            try
            {
                var s = Encryption.Decrypt(GlobalVariables.LoadFromLinkString, "logindetailslink");
                var array = s.Split(',');
                DateTime expiry = DateTime.Parse(array[4]);
                if (DateTime.Now.Subtract(expiry) < new TimeSpan(0, 5, 0))
                {
                    App.Settings.URL = array[0];
                    App.Settings.Port = int.Parse(array[1]);
                    App.Settings.UserID = array[2];
                    App.Settings.Password = array[3];
                    ClientFactory.InvalidateUser();
                    new LocalConfiguration<ConnectionSettings>().Delete();
                    new LocalConfiguration<ConnectionSettings>().Save(App.Settings);
                    App.Settings = new LocalConfiguration<ConnectionSettings>().Load();
                    if (App.Current.Properties.ContainsKey("SessionID"))
                        App.Current.Properties.Remove("SessionID");
                    MobileUtils.SaveToSecureStorage();
                }
                else
                    GlobalVariables.LoadFromLinkString = "Link has expired";
            }
            catch (Exception e)
            {
                if (String.IsNullOrWhiteSpace(App.Settings.URL))
                    LoadDemoSettings(App.Settings);
            }
        }

        public static void LoadDemoSettings(ConnectionSettings settings)
        {
            settings.URL = "http://demo.prsdigital.com.au";
            settings.Port = 8003;
            settings.UserID = "GUEST";
            settings.Password = "guest";
        }


        private static async Task<bool> Retry(Func<Task<bool>> action, int interval, int retryCount = 3)
        {
            bool flag = false;
            List<Exception> source = new List<Exception>();
            TimeSpan delay = TimeSpan.FromMilliseconds((double)interval);
            for (int index = 0; index < retryCount; ++index)
            {
                try
                {
                    flag = await action();
                    if (flag)
                        return true;
                    Task.Delay(delay).Wait();
                }
                catch (Exception ex)
                {
                    if (source.All<Exception>((Func<Exception, bool>)(x => x.Message != ex.Message)))
                        source.Add(ex);
                    Task.Delay(delay).Wait();
                }
            }
            if (!flag && !source.Any<Exception>())
                return false;
            if (source.Count<Exception>() == 1)
                throw source[0];
            if (source.Count<Exception>() > 1)
                throw new AggregateException((IEnumerable<Exception>)source);
            return flag;
        }


        public static async Task<bool> IsPermitted(PermissionType permissiontype)
        {
            try
            {
                Permission permission = (Permission)permissiontype;

                PermissionStatus status = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
                if (status == PermissionStatus.Granted)
                    return true;
                Dictionary<Permission, PermissionStatus> statuses = await CrossPermissions.Current.RequestPermissionsAsync(permission);
                if (statuses[permission] == PermissionStatus.Granted)
                    return true;
                return false;
            }
            catch (System.Threading.Tasks.TaskCanceledException ex)
            {
                return false;
            }            

            //request.Wait();
            //var statuses = request.Result;
            //return (statuses.ContainsKey(permission) && (statuses[permission] == PermissionStatus.Granted));

            //PermissionStatus status = PermissionStatus.Unknown;

            //var result = Retry(async () =>
            //{
            //    status = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
            //    if (status != PermissionStatus.Granted)
            //    {
            //        var results = await CrossPermissions.Current.RequestPermissionsAsync(permission);
            //        if (results.ContainsKey(permission))
            //            status = results[permission];
            //    }

            //    return status == PermissionStatus.Granted;

            //}, 5000, 3);

            //result.Wait();

            //return result.Result;
        }


        public static async Task<bool> CheckPermissions(PermissionType permissiontype)
        {
            Permission permission = (Permission)permissiontype;
            var permissionStatus = await CrossPermissions.Current.CheckPermissionStatusAsync(permission);
            bool request = false;
            if (permissionStatus == PermissionStatus.Denied)
            {
                if (String.Equals(Device.RuntimePlatform,Device.iOS))
                {

                    var title = $"{permission} Permission";
                    var question = $"To use this plugin the {permission} permission is required. Please go into Settings and turn on {permission} for the app.";
                    var positive = "Settings";
                    var negative = "Maybe Later";
                    var task = Application.Current?.MainPage?.DisplayAlert(title, question, positive, negative);
                    if (task == null)
                        return false;

                    var result = await task;
                    if (result)
                    {
                        CrossPermissions.Current.OpenAppSettings();
                    }

                    return false;
                }

                request = true;

            }

            if (request || permissionStatus != PermissionStatus.Granted)
            {
                var newStatus = await CrossPermissions.Current.RequestPermissionsAsync(permission);
                if (newStatus.ContainsKey(permission) && newStatus[permission] != PermissionStatus.Granted)
                {
                    var title = $"{permission} Permission";
                    var question = $"To use the plugin the {permission} permission is required.";
                    var positive = "Settings";
                    var negative = "Maybe Later";
                    var task = Application.Current?.MainPage?.DisplayAlert(title, question, positive, negative);
                    if (task == null)
                        return false;

                    var result = await task;
                    if (result)
                    {
                        CrossPermissions.Current.OpenAppSettings();
                    }
                    return false;
                }
            }

            return true;
        }
    
    }
}
