using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Gms.Common;
using Android.OS;
using Android.Speech.Tts;
using Android.Util;
using Android.Widget;
using Newtonsoft.Json.Linq;
using Plugin.DeviceInfo;
using SQLite.Net;
using SQLite.Net.Platform.XamarinAndroid;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Xamarin.Auth;
using XLabs;
using XLabs.Caching;
using XLabs.Caching.SQLite;
using XLabs.Enums;
using XLabs.Forms;
using XLabs.Forms.Services;
using XLabs.Ioc;
using XLabs.Platform.Device;
using XLabs.Platform.Mvvm;
using XLabs.Platform.Services;
using XLabs.Platform.Services.Email;
using XLabs.Platform.Services.Media;
using XLabs.Serialization;
using XLabs.Serialization.JsonNET;

namespace ZicMoove.Droid
{
    using Android.Runtime;
    using Android.Support.V4.App;
    using Android.Support.V4.Content;
    using ZicMoove.Interfaces;
    using Data;
    using Droid.OAuth;
    using Helpers;
    using Interfaces;
    using Model.Auth.Account;
    using static Android.Manifest;
    using Settings;
    using Model.Auth;
    using Com.Paypal.Android.Sdk.Payments;
    using Java.Math;
    using Org.Json;
    using Xamarin.Forms;
    using ViewModels.UserProfile;

    [Activity(
        Name = Constants.ApplicationName + ".MainActivity",
        Label = Constants.ApplicationLabel,
        Theme = "@style/MainTheme",
        Icon = "@drawable/icon",
        MainLauncher = true,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    [IntentFilter(new[] { Intent.ActionMain },
    Categories = new[] { Intent.CategoryLauncher },
    Icon = "@drawable/icon")]
    public class MainActivity :

        // global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity,
        XFormsCompatApplicationDroid,
        IPlatform, IComponentContext
    {
        private PayPalConfiguration config = new PayPalConfiguration()
         .Environment(PayPalConfiguration.EnvironmentSandbox)
            .MerchantName("Yavsc")
            .LanguageOrLocale("fr")
            .RememberUser(true)
            .AcceptCreditCards(true) // needs card.io
                                     // TODO   .MerchantPrivacyPolicyUri(new Uri("http://"))
                                     // TODO  .MerchantUserAgreementUri(new Uri("http://"))
            .ClientId(Constants.PaypalClientId)
            .SandboxUserPassword(Constants.PaypalClientSecret)
            ;

        protected override void OnCreate(Bundle bundle)
        {
            TabLayoutResource = Resource.Layout.Tabbar;
            ToolbarResource = Resource.Layout.Toolbar;
            base.OnCreate(bundle);
            XamSvg.Setup.InitSvgLib();
            // FIXME usefull?
            SetPersistent(true);
            // global::Xamarin.Forms.Forms.SetTitleBarVisibility(Xamarin.Forms.AndroidTitleBarVisibility.Never);

            //var tb = FindViewById<Android.Support.V7.Widget.Toolbar>(ToolbarResource);
            // FIXME tb is null
            var stb = new Android.Support.V7.Widget.Toolbar(this);
            SetSupportActionBar(stb);
            var tb = new Toolbar(this);
            SetActionBar(tb);

            if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
            {
                Android.Webkit.WebView.SetWebContentsDebuggingEnabled(true);
            }

            IXFormsApp<XFormsCompatApplicationDroid> app = null;
            if (!Resolver.IsSet)
            {
                var xfapp = new XFormsCompatAppDroid();
                this.SetIoc(xfapp);

            }
            else
            {
                app = Resolver.Resolve<IXFormsApp>() as IXFormsApp<XFormsCompatApplicationDroid>;
                if (app != null)
                    app.AppContext = this;
            }

            global::Xamarin.Forms.Forms.Init(this, bundle);
            global::Xamarin.FormsMaps.Init(this, bundle);

            Xamarin.Forms.Forms.ViewInitialized += (sender, e) =>
            {
                if (!string.IsNullOrWhiteSpace(e.View.StyleId))
                {
                    e.NativeView.ContentDescription = e.View.StyleId;
                }
            };

            var fapp = new ZicMoove.App(this);


            LoadApplication(fapp);

            var componentName = StartService(new Intent(this, typeof(YavscChooserTargetService)));

            // TabLayoutResource = Resource.Layout.Tabbar;
            // ToolbarResource = Resource.Layout.Toolbar;
            /*
            base.OnCreate(bundle);
            global::Xamarin.Forms.Forms.Init(this, bundle);
            global::Xamarin.FormsMaps.Init(this, bundle);
            LoadApplication(new App(this));
            /* var x = typeof(Themes.DarkThemeResources);
             x = typeof(Themes.LightThemeResources);
             x = typeof(Themes.Android.UnderlineEffect); */

            var intent = new Intent(this, typeof(PayPalService));
            intent.PutExtra(PayPalService.ExtraPaypalConfiguration, config);
            this.StartService(intent);

        }
        public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
        {
            base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
            if (requestCode == Constants.AllowBeATarget)
            {
                if (grantResults.Length > 0)
                {
                    if (grantResults[0] == Android.Content.PM.Permission.Granted)
                    {
                        // yay!
                    }
                    else
                    {
                        // Should we show an explanation?
                        if (ActivityCompat.ShouldShowRequestPermissionRationale(this,
                                Permission.BindChooserTargetService))
                        {
                            //Show permission explanation dialog...
                            // Show an expanation to the user *asynchronously* -- don't block
                            // this thread waiting for the user's response! After the user
                            // sees the explanation, try again to request the permission.
                            throw new NotImplementedException();
                        }
                        else
                        {
                            //Never ask again selected, or device policy prohibits the app from having that permission.
                            //So, disable that feature, or fall back to another situation...
                        }
                    }
                }
            }
        }
        private SimpleContainer SetIoc(XFormsCompatAppDroid app)
        {
            var resolverContainer = new SimpleContainer();


            app.Init(this);

            var documents = app.AppDataDirectory;
            var pathToDatabase = Path.Combine(documents, "xforms.db");

            resolverContainer.Register<IDevice>(t => AndroidDevice.CurrentDevice)
                .Register<IDisplay>(t => t.Resolve<IDevice>().Display)
                .Register<IFontManager>(t => new FontManager(t.Resolve<IDisplay>()))
                .Register<IEmailService, EmailService>()
                .Register<IMediaPicker, MediaPicker>()
                .Register<ITextToSpeechService, XLabs.Platform.Services.TextToSpeechService>()
                .Register<IDependencyContainer>(resolverContainer)
                .Register<IXFormsApp>(app)
                .Register<ISecureStorage>(t => new KeyVaultStorage(t.Resolve<IDevice>().Id.ToCharArray()))
                .Register<IJsonSerializer, JsonSerializer>()
                .Register<ICacheProvider>(
                    t => new SQLiteSimpleCache(new SQLitePlatformAndroid(),
                        new SQLiteConnectionString(pathToDatabase, true), t.Resolve<IJsonSerializer>()))
                .RegisterSingle<UserProfileViewModel,UserProfileViewModel>();
            Resolver.SetResolver(resolverContainer.GetResolver());
            return resolverContainer;
        }

        public bool EnablePushNotifications(bool enable)
        {
            if (enable)
                return StartNotifications();
            else
                return StopNotifications();
        }

        private string gCMStatusMessage = null;
        public string GCMStatusMessage
        {
            get
            {
                return gCMStatusMessage;
            }
        }

        public App AppContext
        {
            get; set;
        }

        bool StartNotifications()
        {
            if (IsPlayServicesAvailable(out gCMStatusMessage))
            {
                var intent = new Intent(this, typeof(GcmRegistrationIntentService));
                StartService(intent);
                return true;
            }
            return false;
        }


        bool StopNotifications()
        {
            return StopService(new Intent(this, typeof(GcmRegistrationIntentService)));
        }

        public void RevokeAccount(string userName)
        {

            var accStore = AccountStore.Create(this);
            var accounts = accStore.FindAccountsForService(Constants.ApplicationLabel);

            accStore.Delete(
                    accounts.Where(a => a.Username == userName).FirstOrDefault()
                    , Constants.ApplicationLabel);
            Toast.MakeText(this,
                Resource.String.yavscIdentRemoved
                , ToastLength.Short);
        }

        public void OpenWeb(string Uri)
        {
            var u = global::Android.Net.Uri.Parse(Uri);
            Intent i = new Intent(Intent.ActionView, u);
            StartActivity(i);
        }


        protected override void OnStart()
        {
            base.OnStart();
            if (MainSettings.PushNotifications)
                StartNotifications();
            long queryId = Intent.GetLongExtra("BookQueryId", 0);

            if (queryId > 0)
            {
                Task.Run(async () =>
                {
                    var query = DataManager.Instance.BookQueries.LocalGet(queryId);
                    App.ShowBookQuery(query);
                });
            }
        }


        public bool IsPlayServicesAvailable(out string msgText)
        {
            int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(this);
            if (resultCode != ConnectionResult.Success)
            {
                if (GoogleApiAvailability.Instance.IsUserResolvableError(resultCode))
                    msgText = GoogleApiAvailability.Instance.GetErrorString(resultCode);
                else
                {
                    msgText = "Sorry, this device is not supported";
                    Finish();
                }
                return false;
            }
            else
            {
                msgText = "Google Play Services is available.";
                return true;
            }
        }

        public async Task<IEnumerable<Account>> GetAndroidAccounts()
        {
            return await Task.Run(() =>
            {
                var manager = AccountStore.Create(this);
                return manager.FindAccountsForService(Constants.ApplicationLabel);
            });
        }

        public void AddAccount()
        {
            var auth = new YaOAuth2Authenticator(
                                clientId: Constants.APIKey,
                                clientSecret: Constants.APISecret,
                                scope: Constants.Scope,
                                authorizeUrl: new Uri(Constants.AuthorizeUrl),
                                redirectUrl: new Uri(Constants.RedirectUrl),
                                accessTokenUrl: new Uri(Constants.AccessTokenUrl));
            Intent loginIntent = auth.GetUI(this);
            var accStore = AccountStore.Create(this);
            auth.Completed += (sender, eventArgs) =>
            {
                if (eventArgs.IsAuthenticated)
                {
                    int expires_in = int.Parse(eventArgs.Account.Properties["expires_in"]);
                    var tokens = new Tokens
                    {
                        AccessToken = eventArgs.Account.Properties["access_token"],
                        RefreshToken = eventArgs.Account.Properties["refresh_token"],
                        ExpiresIn = expires_in,
                        TokenType = eventArgs.Account.Properties["token_type"]
                    };
                    RunOnUiThread(

                       async () =>
                       {
                           using (var client = new HttpClient())
                           {
                               // get me
                               using (var request = new HttpRequestMessage(HttpMethod.Get, Constants.UserInfoUrl))
                               {
                                   request.Headers.Authorization =
                                   new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", tokens.AccessToken);

                                   using (var response = await client.SendAsync(request))
                                   {
                                       response.EnsureSuccessStatusCode();
                                       string userJson = await response.Content.ReadAsStringAsync();
                                       JObject jactiveUser = JObject.Parse(userJson);
                                       Account acc = eventArgs.Account;

                                       var uid = jactiveUser["Id"].Value<string>();
                                       var username = jactiveUser["UserName"].Value<string>();
                                       var roles = jactiveUser["Roles"].Values<string>().ToList();
                                       var emails = jactiveUser["EMails"].Values<string>().ToList();
                                       var avatar = jactiveUser["Avatar"].Value<string>();
                                       var address = jactiveUser["Avatar"].Value<string>();
                                       var newuser = new User
                                       {
                                           UserName = username,
                                           EMails = emails,
                                           Roles = roles,
                                           Id = uid,
                                           YavscTokens = tokens,
                                           Avatar = avatar,
                                           Address = address
                                       };

                                       MainSettings.SaveUser(newuser);
                                       accStore.Save(acc, Constants.ApplicationLabel);
                                   }
                               }
                           }
                       });
                }
            };
            auth.Error += Auth_Error;
            StartActivity(loginIntent);
        }

        private void Auth_Error(object sender, AuthenticatorErrorEventArgs e)
        {
            // TODO handle
        }





        public T Resolve<T>()
        {
            return (T)Resolver.Resolve(typeof(T));
        }

        public object Resolve(Type t)
        {
            return Resolver.Resolve(t);
        }

        protected override void OnSaveInstanceState(Bundle outState)
        {
            // TODO Save instance
            base.OnSaveInstanceState(outState);
        }
        public override void OnStateNotSaved()
        {
            base.OnStateNotSaved();
        }
        public override void OnRestoreInstanceState(Bundle savedInstanceState, PersistableBundle persistentState)
        {
            base.OnRestoreInstanceState(savedInstanceState, persistentState);
        }

        private void CheckSharing()
        {
            // .BIND_CHOOSER_TARGET_SERVICE

            // Here, thisActivity is the current activity
            if (ContextCompat.CheckSelfPermission(this,
                           Permission.BindChooserTargetService) != Android.Content.PM.Permission.Granted)
            {


                ActivityCompat.RequestPermissions(this,
                        new String[] { Permission.BindChooserTargetService },
                        Constants.AllowBeATarget);

                // Constants.AllowReadContacts is an
                // app-defined int constant. The callback method gets the
                // result of the request.

            }
        }

        public void Pay(double amount, PayMethod method, string name = null)
        {
            if (name == null) name = $"Votre commande {Constants.ApplicationLabel}";
            var payment = new PayPalPayment(new BigDecimal(amount), "EUR", "the item",
                PayPalPayment.PaymentIntentOrder);

            var intent = new Intent(this, typeof(PaymentActivity));
            intent.PutExtra(PayPalService.ExtraPaypalConfiguration, config);
            intent.PutExtra(PaymentActivity.ExtraPayment, payment);
            this.StartActivityForResult(intent, (int)RequestCode.PayImmediate);
        }

        protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
        {
            if (requestCode == (int)RequestCode.PayDelayed)
                if (resultCode == Result.Ok)
                {
                    var confirm = data.GetParcelableExtra(PaymentActivity.ExtraResultConfirmation);
                    if (confirm != null)
                    {
                        try
                        {
                            Log.Info("xam.paypal.test", confirm.ToString());

                            // TODO: send 'confirm' to your server for verification.
                            // see https://developer.paypal.com/webapps/developer/docs/integration/mobile/verify-mobile-payment/
                            // for more details.

                        }
                        catch (JSONException e)
                        {
                            Log.Error("xam.paypal.test", "something went really wrong here: ", e);
                        }
                    }
                }
                else if (resultCode == Result.Canceled)
                {
                    Log.Info("xam.paypal.test", "Canceled.");
                }
                else if ((int)resultCode == PaymentActivity.ResultExtrasInvalid)
                {
                    Log.Info("xam.paypal.test", "Invalid Payment or PayPalConfiguration.");
                }
        }


        protected override void OnDestroy()
        {
            this.StopService(new Intent(this, typeof(PayPalService)));
            base.OnDestroy();
        }

        enum RequestCode : int
        {
            PayImmediate = 1,
            PayDelayed
        }
        private static string imagesFolder = null;
        public static string ImagesFolder
        {
            get
            {
                if (imagesFolder != null) return imagesFolder;
                imagesFolder = Constants.ImagePath.GetSpecialFolder();
                return imagesFolder;
            }
        }

        public void UpdateAppImages()
        {
            var images = ImagesFolder;

            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(Constants.YavscHomeUrl);
                var targets = DataManager.Instance.Activities.Select(
                    a => new string[2] { a.Photo, a.Code }
                    ).ToArray();
                foreach (var photo in targets)
                {
                    if (photo[0] != null)
                    {
                        var streamtask = client.GetStreamAsync(photo[0]);
                        streamtask.Wait();
                        if (streamtask.IsCompleted)
                        {
                            using (streamtask.Result)
                            {
                                FileInfo fi = new FileInfo(Path.Combine(images, $"{photo[1]}.svg"));
                                using (var ostr = fi.OpenWrite())
                                {
                                    streamtask.Result.CopyTo(ostr);
                                }
                            }
                        }
                        var acode = photo[1];
                        var act = DataManager.Instance.Activities.LocalGet(acode);
                        act.LocalPhoto = Path.Combine(images, $"{acode}.svg");
                    }
                }
                DataManager.Instance.Activities.SaveEntity();
            }
        }
    }
}


