using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using C4IT.FASD.Security;
using C4IT.Graphics;
using C4IT.Logging;
using C4IT.MultiLanguage;
using FasdDesktopUi.Basics;
using FasdDesktopUi.Basics.Helper;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.Services.Models;
using FasdDesktopUi.Pages.CustomMessageBox;
using FasdDesktopUi.Pages.PhoneSettingsPage;
using FasdDesktopUi.Pages.SearchPage;
using FasdDesktopUi.Pages.SettingsPage;
using FasdDesktopUi.Pages.ShortCutPage;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using static C4IT.Logging.cLogManager;

namespace FasdDesktopUi
{
    public partial class App : Application
    {
        static public string PhoneMonitorPipeName;


        static public Mutex AppMutex = null;
        static public string PipeName = "";

        static public System.Windows.Forms.ToolStripItem M42OptionMenuItem = null;

        public System.Windows.Forms.NotifyIcon notifyIcon = new System.Windows.Forms.NotifyIcon() { Text = $"First Aid Service Desk" };
        public bool UseOsLanguage = string.IsNullOrEmpty(cFasdCockpitConfig.Instance.SelectedLanguage);

        #region Ticketübersicht

        private TrayTicketNotificationManager _ticketTrayNotification;
        private TileScope? _pendingTicketOverviewScope;

        #endregion

        private async void Application_Startup(object sender, StartupEventArgs e)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                InitializeLogger();


                /* Attach debugger befor start
                Console.WriteLine("Waiting for debugger to attach");
                while (!Debugger.IsAttached)
                {
                    Thread.Sleep(100);
                }
                Console.WriteLine("Debugger attached");
                */ 
                Assembly assembly = Assembly.GetExecutingAssembly();
                var ProductName = FileVersionInfo.GetVersionInfo(assembly.Location).ProductName;
                var attribute = (GuidAttribute)assembly.GetCustomAttributes(typeof(GuidAttribute), true)[0];
                var AssemblyGuid = attribute.Value;
                string MutexName = ProductName + AssemblyGuid.ToString();
                var SessionId = 0;
                try
                {
                    SessionId = Process.GetCurrentProcess().SessionId;
                }
                catch { }

                PipeName = MutexName + $".pipe.{SessionId}";
                PhoneMonitorPipeName = PipeName + ".PhoneMonitor." + Guid.NewGuid().ToString();

                if (e.Args.Length > 0)
                {
                    bool shouldShutdown = cAppStartUp.ProcessCommandLine(e.Args);
                    if (shouldShutdown)
                    {
                        Current.Shutdown();
                        return;
                    }
                }

                try
                {
                    AppMutex = new Mutex(false, MutexName);
                    if (!AppMutex.WaitOne(0))
                    {
                        LogEntry("Application already started, exiting...", LogLevels.Info);
                        AppMutex.Dispose();
                        AppMutex = null;
                        Current.Shutdown();
                        return;
                    }
                }
                catch (Exception E)
                {
                    LogEntry("Cannot create application mutex, exiting...", LogLevels.Fatal);
                    LogException(E);
                    Current.Shutdown();
                    return;
                }

                cF4sdPipeClient.RegisterProtocol(cAppStartUp.constUrlProtocol, cAppStartUp.constUrlCommand);

                cMultiLanguageSupport.CurrentLanguage = cFasdCockpitConfig.Instance.SelectedLanguage;


                try
                {
                    FasdSecurity.Init();
                    PrivateSecurePassword.Init();
                }
                catch (Exception E)
                {
                    LogException(E);
                    MessageBox.Show(cMultiLanguageSupport.GetItem("App.Startup.SecurityInitFailed.Text"), cMultiLanguageSupport.GetItem("App.Startup.SecurityInitFailed.Caption"), MessageBoxButton.OK, MessageBoxImage.Error);
                    Current.Shutdown();
                }

                InitializeNotifyIcon();

                //CustomMessageBox.ShowCustomContent("Close case", enumHealthCardStateLevel.None, null, true, new CloseCaseDialogWithTicket());

                await cAppStartUp.StartAsync(e.Args);
                notifyIcon.Visible = true;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                Mouse.OverrideCursor = null;
                LogMethodEnd(CM);
            }
        }

        #region Logger

        private void InitializeLogger()
        {
            cLogManagerFile.CreateInstance(false, SubFolder: "Logs", DebugFlags: new List<string>() { "apivalues", "apitiming" });
            cFasdCockpitCommunicationBase.Debug_apiValues = cLogManager.Instance.CheckDebugFlag("apivalues");
            cFasdCockpitCommunicationBase.Debug_apiTiming = cLogManager.Instance.CheckDebugFlag("apitiming");
            cLogManager.DefaultLogger.LogAssemblyInfo();

            Dispatcher.UnhandledException += Dispatcher_UnhandledException;
            AppDomain.CurrentDomain.UnhandledException += (o, e) => LogException((Exception)e.ExceptionObject, LogLevels.Fatal);
        }

        private void Dispatcher_UnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            LogException(e.Exception, LogLevels.Error);
            e.Handled = true;
        }

        #endregion

        #region NotifyIcon

        public static void HideAllSettingViews()
        {
            SettingsPageView.Instance?.Hide();

        }

        private void NotifyIcon_Click(object sender, EventArgs e)
        {
            try
            {
                if (e is System.Windows.Forms.MouseEventArgs mouseEventArgs)
                    if (mouseEventArgs.Button == System.Windows.Forms.MouseButtons.Right)
                        return;


                var searchView = SearchPageView.Instance;
                if (searchView == null)
                    return;

                if (TryHandleTicketOverviewNotificationClick(searchView))
                    return;

#if isDemo
                if (searchView.IsVisible)
                {
                    searchView.Hide();
                    return;
                }

                if (!searchView.IsVisible)
                    searchView.ActivateSearchView();
                else
                    searchView.BringToFrontPreserveState();

                searchView.ShowTicketOverviewPane();
#else
                if (SearchPageView.Instance.IsVisible)
                    SearchPageView.Instance.Hide();
                else
                    SearchPageView.Instance.ActivateSearchView();
#endif
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void InitializeNotifyIcon()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                NotifyerSupport.LoadSetFromResource("Default", "FasdDesktopUi.Resources.logo_FASD.ico");
                NotifyerSupport.LoadSetFromResource("StartUp", "FasdDesktopUi.Resources.logo_F4SD_flip.ico");
                NotifyerSupport.LoadSetFromResource("OverlayOffline", "FasdDesktopUi.Resources.StateOverlays.Offline", NoRefresh: true)?.CreateSizeMap(0.45f);
                NotifyerSupport.RegisterNotifyControl(notifyIcon);
                NotifyerSupport.SetNotifyIcon("StartUp");

                var assemblyVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion;
                notifyIcon.Text += " version " + assemblyVersion;
                _ticketTrayNotification = new TrayTicketNotificationManager(notifyIcon);
                _ticketTrayNotification.CaptureBaseTooltip();
                _ticketTrayNotification.ApplyTooltip();
                notifyIcon.Click += NotifyIcon_Click;
                notifyIcon.BalloonTipClicked += NotifyIcon_BalloonTipClicked;

                SetUpNotifyIconLanguageOption();

                notifyIcon.ContextMenuStrip = new System.Windows.Forms.ContextMenuStrip() { Visible = true };
                notifyIcon.ContextMenuStrip.Items.Add(SetUpNotifyIconLanguageOption());
                notifyIcon.ContextMenuStrip.Items.Add(cMultiLanguageSupport.GetItem("Menu.Options"), null, NotifyIconOptions_Click);

                M42OptionMenuItem = notifyIcon.ContextMenuStrip.Items.Add(cMultiLanguageSupport.GetItem("M42Settings.SystemTray"), null, (sender, e) =>
                {
                    if (cFasdCockpitCommunicationBase.CockpitUserInfo == null)
                        return;
                    M42SettingsPageView.Instance.Show();
                });
                M42OptionMenuItem.Visible = false;

                notifyIcon.ContextMenuStrip.Items.Add(cMultiLanguageSupport.GetItem("PhoneSettings.SystemTray"), null, (sender, e) =>
                {
                    PhoneSettingsPage.Instance.Show();
                });

                notifyIcon.ContextMenuStrip.Items.Add(new System.Windows.Forms.ToolStripSeparator());

                notifyIcon.ContextMenuStrip.Items.Add(cMultiLanguageSupport.GetItem("Menu.KeyBoardShortcuts"), null, (sender, e) =>
                {
                    ShortCutPageView.Instance.Show();
                });
                notifyIcon.ContextMenuStrip.Items.Add(new System.Windows.Forms.ToolStripSeparator());
                notifyIcon.ContextMenuStrip.Items.Add(cMultiLanguageSupport.GetItem("Menu.About"), null, NotifyIconAbout_Click);
                notifyIcon.ContextMenuStrip.Items.Add(new System.Windows.Forms.ToolStripSeparator());
                notifyIcon.ContextMenuStrip.Items.Add(cMultiLanguageSupport.GetItem("Menu.Restart"), null, NotifyIconRestart_Click);
                notifyIcon.ContextMenuStrip.Items.Add(cMultiLanguageSupport.GetItem("Menu.Quit"), null, NotifyIconQuit_Click);
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        #region Ticketübersicht

        private bool TryHandleTicketOverviewNotificationClick(SearchPageView searchView)
        {
            if (searchView == null)
                return false;

            if (!HasPendingTicketOverviewNotification())
                return false;

            if (!searchView.IsVisible)
                searchView.ActivateSearchView();
            else
                searchView.BringToFrontPreserveState();

            searchView.ShowTicketOverviewPaneForScope(PendingTicketOverviewScope);
            ClearTicketOverviewTrayNotification();
            return true;
        }

        private void NotifyIcon_BalloonTipClicked(object sender, EventArgs e)
        {
            try
            {
                SearchPageView.Instance?.BringToFrontPreserveState();
                SearchPageView.Instance?.ShowTicketOverviewPaneForScope(PendingTicketOverviewScope);
                ClearTicketOverviewTrayNotification();
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private bool HasPendingTicketOverviewNotification()
        {
            return _ticketTrayNotification?.HasNotification ?? false;
        }

        public void ShowTicketOverviewTrayNotification(string message)
        {
            try
            {
                _ticketTrayNotification?.Show(message);
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
        }

        public void ClearTicketOverviewTrayNotification()
        {
            try
            {
                _pendingTicketOverviewScope = null;
                _ticketTrayNotification?.Clear();
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
        }

        public void SetTicketOverviewNotificationScope(TileScope? scope)
        {
            _pendingTicketOverviewScope = scope;
        }

        public TileScope? PendingTicketOverviewScope => _pendingTicketOverviewScope;

        #endregion

        private System.Windows.Forms.ToolStripItem SetUpNotifyIconLanguageOption()
        {
            try
            {
                var output = new System.Windows.Forms.ToolStripMenuItem() { Text = cMultiLanguageSupport.GetItem("Menu.SelectLanguage") };

                var languages = cMultiLanguageSupport.GetSupportedLanguages();
                var stripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
                var defaultFormat = cMultiLanguageSupport.GetItem("Menu.SelectLanguage.Default");
                stripMenuItem.Text = string.Format(defaultFormat, cMultiLanguageSupport.GetOsDefault());
                stripMenuItem.Image = cMultiLanguageSupport.GetImage(".");
                stripMenuItem.Click += ToolStripMenuLanguage_Click;
                if (UseOsLanguage)
                    stripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;

                output.DropDownItems.Add(stripMenuItem);
                foreach (var Entry in languages)
                {
                    stripMenuItem = new System.Windows.Forms.ToolStripMenuItem
                    {
                        Text = Entry,
                        Tag = Entry,
                        Image = cMultiLanguageSupport.GetImage(Entry)
                    };
                    stripMenuItem.Click += ToolStripMenuLanguage_Click;
                    if (!UseOsLanguage && (cMultiLanguageSupport.CurrentLanguage == Entry))
                        stripMenuItem.CheckState = System.Windows.Forms.CheckState.Checked;
                    output.DropDownItems.Add(stripMenuItem);
                }

                return output;
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return null;
        }

        private void ToolStripMenuLanguage_Click(object sender, EventArgs e)
        {
            var OldLanguage = cMultiLanguageSupport.CurrentLanguage;
            string NewLanguage = null;

            if (sender is System.Windows.Forms.ToolStripMenuItem selectedLanguageStripMenuItem)
            {
                if (selectedLanguageStripMenuItem.OwnerItem is System.Windows.Forms.ToolStripMenuItem parentStripMenuItem)
                {
                    foreach (System.Windows.Forms.ToolStripMenuItem Entry in parentStripMenuItem.DropDownItems)
                    {
                        Entry.Checked = Entry == selectedLanguageStripMenuItem;
                    }
                }

                if (selectedLanguageStripMenuItem.Tag is string stripMenuItemTag)
                {
                    if (!string.IsNullOrWhiteSpace(stripMenuItemTag))
                        NewLanguage = stripMenuItemTag;
                }
            }

            UseOsLanguage = NewLanguage == null;
            cMultiLanguageSupport.CurrentLanguage = NewLanguage;

            cFasdCockpitConfig.Instance.SelectedLanguage = NewLanguage;
            cFasdCockpitConfig.Instance.Save("SelectedLanguage");

            if (OldLanguage == NewLanguage)
                return;

            //var dialogResult = MessageBox.Show(cMultiLanguageSupport.GetItem("Menu.SelectLanguage.RestartDialog.Text"), cMultiLanguageSupport.GetItem("Menu.SelectLanguage.RestartDialog.Caption"), MessageBoxButton.YesNo, MessageBoxImage.Information);

            var dialogResult = CustomMessageBox.Show(cMultiLanguageSupport.GetItem("Menu.SelectLanguage.RestartDialog.Text"), cMultiLanguageSupport.GetItem("Menu.SelectLanguage.RestartDialog.Caption"), enumHealthCardStateLevel.Info, null, true);

            if (dialogResult == true)
            {
                System.Windows.Forms.Application.Restart();
                Current.Shutdown();
            }
        }

        private void NotifyIconOptions_Click(object sender, EventArgs e)
        {
            try
            {
                var settingsView = SettingsPageView.Create();

                if (settingsView.IsVisible)
                    settingsView.Hide();
                else
                    settingsView.Show();
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void NotifyIconAbout_Click(object sender, EventArgs e)
        {
            var assemblyVersion = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion;

            var messageText = cMultiLanguageSupport.GetItem("Menu.TrademarkNotice");

            CustomMessageBox.Show(messageText, $"First Aid Service Desk ({assemblyVersion})", enumHealthCardStateLevel.Info);
        }

        private async void NotifyIconRestart_Click(object sender, EventArgs e)
        {
            try
            {
                var shouldRestart = await cSupportCaseDataProvider.SupportTicketActiveNoticeAsync();

                if (!shouldRestart)
                    return;

                System.Windows.Forms.Application.Restart();
                Current.Shutdown();
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private async void NotifyIconQuit_Click(object sender, EventArgs e)
        {
            try
            {
                var shouldQuit = await cSupportCaseDataProvider.SupportTicketActiveNoticeAsync();

                if (!shouldQuit)
                    return;

                Current.Shutdown();
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

#endregion

        private async void Application_Exit(object sender, ExitEventArgs e)
        {
            cF4sdUserInfo userInfo = null;
            ConfiguredTaskAwaitable? closeUserSessionTask = null;
            lock (cFasdCockpitCommunicationBase.CockpitUserInfoLock) 
            { 
                userInfo = cFasdCockpitCommunicationBase.CockpitUserInfo; 
            }
            if (userInfo?.Id.Equals(Guid.Empty) is false) 
            {
                closeUserSessionTask = cFasdCockpitCommunicationBase.Instance?.CloseUserSession(cFasdCockpitConfig.SessionId).ConfigureAwait(false); 
            }

            await cFasdCockpitCommunicationBase.Instance?.TerminateAsync();

            if (notifyIcon != null)
            {
                try
                {
                    cConnectionStatusHelper.Instance.IsActive = false;
                    notifyIcon.Visible = false;
                    notifyIcon.Dispose();
                    cAppStartUp.Terminate();
                }
                catch { }
            }

            if (AppMutex != null)
            {
                try
                {
                    AppMutex.ReleaseMutex();
                }
                catch { }

                try
                {
                    AppMutex.Dispose();
                }
                catch { }
            }

            try
            {
                var _now = DateTime.UtcNow;
                bool _validSend = true;
                while ((DateTime.UtcNow - _now).TotalSeconds < 6 && _validSend)
                    _validSend = cF4sdPipeClient.Send("STOP", PhoneMonitorPipeName);
            }
            catch { }

            if (closeUserSessionTask is ConfiguredTaskAwaitable _t)
                await _t;
        }
    }
}
