using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using C4IT.Logging;
using C4IT.Matrix42.WebClient;
using C4IT.MultiLanguage;

using FasdDesktopUi.Basics.UserControls.AdaptableIcon;
using FasdDesktopUi.Pages.SettingsPage;

using Microsoft.Web.WebView2.Core;
using Microsoft.Web.WebView2.Wpf;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

using static C4IT.Logging.cLogManager;

namespace FasdDesktopUi.Pages.M42AuthenticationPage
{
    public partial class F4sdM42FormsAuthentication : Window
    {
        private string _M42Server = null;
        private Uri _logonUrl = null;
        private bool regainToken = false;
        private cM42UserInfoResult userInfoM42 = null;
        private bool Reauthenticate = false;

        public cF4SdUserInfoChange UserInfoChange { get; private set; } = null;

        public F4sdM42FormsAuthentication(bool Reauthenticate)
        {
            InitializeComponent();
            NoAccessTokenMessage.Visibility = Visibility.Collapsed;
            this.Reauthenticate = Reauthenticate;
        }

        private void CloseIcon_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            DialogResult = false;
            Close();
        }

        private void StartForm()
        {
            _logonUrl = new Uri($"https://{_M42Server}/m42Services/api/sts/authorize?client_id=ServiceStore.NewUX&scope=urn:matrix42NewUX&response_type=token&autoLogin=true");
            WebLogon.Source = _logonUrl;
        }

        private async void WebLogon_Loaded(object sender, RoutedEventArgs e)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                // set the data path for the WebView2 component
                var _webViewConfigPath = cLogManagerFile.GetDefaultPath(false, SubFolder: "WebViewData");
                _webViewConfigPath = System.IO.Path.GetDirectoryName(_webViewConfigPath);
                CultureInfo culture = new CultureInfo(cMultiLanguageSupport.CurrentLanguage);
                var webEnv = await CoreWebView2Environment.CreateAsync(userDataFolder: _webViewConfigPath, options: new CoreWebView2EnvironmentOptions() { Language = culture.TextInfo.CultureName, AllowSingleSignOnUsingOSPrimaryAccount = true });
                var _co = webEnv.CreateCoreWebView2ControllerOptions();
                await WebLogon.EnsureCoreWebView2Async(webEnv, _co);

                // modify the header text
                if (Reauthenticate)
                {
                    TextHeader.Text = cMultiLanguageSupport.GetItem("M42Settings.FormsAuthentication.HeaderResign");
                    this.ShowInTaskbar = true;
                }

                // check if we have a correct M42 config
                _M42Server = cCockpitConfiguration.Instance?.m42ServerConfiguration?.Server;
                if (string.IsNullOrEmpty(_M42Server) || cFasdCockpitCommunicationBase.CockpitUserInfo == null)
                {
                    Close();
                    return; ;
                }

                // start the logon page
                StartForm();
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }


        }

        private async void WebLogon_NavigationStarting(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NavigationStartingEventArgs e)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                var _u = e.Uri;
                Debug.WriteLine($"nav.start: {_u}");

                var _uri = new Uri(_u);
                var _host = _uri.Host.ToLowerInvariant();
                var _path = _uri.LocalPath.ToLowerInvariant();
                var _frag = _uri.Fragment;
                var _query = _uri.Query;
                string M42Code = null;
                string M42State = null;
                if (_frag == null)
                    _frag = "";

                if (_host == _M42Server.ToLowerInvariant() && _path == "/wm/" && _query.Contains("code="))
                {
                    var _tmpQuery = _query;
                    if (_tmpQuery.StartsWith("?"))
                        _tmpQuery = _tmpQuery.Remove(0, 1);
                    var _arrItems = _tmpQuery.Split('&');
                    foreach (var item in _arrItems)
                    {
                        var _props = item.Split('=');
                        if (_props.Length == 2)
                        {
                            switch (_props[0])
                            {
                                case "code":
                                    M42Code = _props[1];
                                    break;
                                case "state":
                                    M42State = _props[1];
                                    break;
                            }
                        }
                    }
                    WebLogon.Stop();
                    WebLogon.CoreWebView2.Navigate(_logonUrl.AbsoluteUri);
                }

                if (_host == _M42Server.ToLowerInvariant() && _path == "/wm/" && _frag.Contains("#access_token="))
                {
                    if (regainToken)
                    {
                        regainToken = false;
                        return;
                    }

                    WebLogon.Stop();
                    WebLogon.Visibility = Visibility.Collapsed;
                    var _token = await ProcessAccessTokenAsync(_frag);
                    if (_token is null)
                        NoAccessTokenMessage.Visibility = Visibility.Visible;
                    else
                    {
                        cF4sdUserInfo userInfo;
                        lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock)
                        {
                            userInfo = cFasdCockpitCommunicationBase.CockpitUserInfo;
                        }
                        var _TokenRegistration = new cF4SDTokenRegistration()
                        {
                            UserId = userInfo.Id,
                            TokenType = cF4SDTokenRegistration.enumTokenType.M42Bearer,
                            Secret = _token,
                            AutoCreatePermanent = true
                        };

                        var _userInfoChange = await cFasdCockpitCommunicationBase.Instance.RegisterExternalTokenAsync(_TokenRegistration);

                        if (_userInfoChange is null)
                        {
                            NoAccessTokenMessage.Visibility = Visibility.Visible;
                        }
                        else
                        {
                            UserInfoChange = _userInfoChange;
                            DialogResult = true;
                            Close();
                        }

                    }

                }

            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        private async Task<string> ProcessAccessTokenAsync(string Fragment)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                var _arrParameters = Fragment.Split('&');
                string _AccessToken = null;
                foreach (var _arrParam in _arrParameters)
                {
                    var _items = _arrParam.Split('=');
                    if (_items.Length == 2 && _items[0] == "#access_token")
                        _AccessToken = _items[1];
                }

                var _AccessPayload = cM42TokenPayload.GetAccessPayload(_AccessToken);

                if (_AccessPayload != null && _AccessPayload.UserObjectId != Guid.Empty)
                {

                    var M42WebClient = new cM42WebClient(_M42Server);
                    M42WebClient.SetBearerToken(_AccessToken);
                    var _res = await M42WebClient.Open();
                    if (_res == cM42WebClient.eReason.ok)
                    {
                        userInfoM42 = await M42WebClient.GetUserInfoAsync();
                        if (userInfoM42.Reason == cM42WebClient.eReason.ok)
                        {
                            return _AccessToken;
                        }
                    }
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return null;

        }

        public static cF4SdUserInfoChange M42FormBasedAuthenticationDelegate()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                var logonPage = new F4sdM42FormsAuthentication(Reauthenticate: true);
                var _ret = logonPage.ShowDialog();

                if (_ret == true)
                    return logonPage.UserInfoChange;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return null;

        }

        private void butRefresh_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                WebLogon.Stop();
                WebLogon.Source = new Uri("about:blank");
                _logonUrl = new Uri($"https://{_M42Server}/m42Services/api/sts/authorize?client_id=ServiceStore.NewUX&scope=urn:matrix42NewUX&response_type=token&autoLogin=true");
                WebLogon.Source = _logonUrl;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        private void butClearCookies_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                if (WebLogon?.CoreWebView2?.CookieManager != null)
                    WebLogon.CoreWebView2.CookieManager.DeleteAllCookies();
                butRefresh_MouseLeftButtonUp(sender, null);
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }
    }

    public class cM42UserInfo
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Guid ObjectId { get; set; }
    }
}
