using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
using Vinno.FIS.Sonopost.Common;
using Vinno.FIS.Sonopost.Features.Network;
using Vinno.FIS.Sonopost.Features.Oled;
using Vinno.FIS.Sonopost.Helpers;
using Vinno.FIS.Sonopost.Managers;
using Vinno.FIS.Sonopost.Managers.Interfaces;
using Vinno.FIS.Sonopost.Settings;
using Vinno.IUS.Common.Log;

namespace Vinno.FIS.Sonopost
{
    /// <summary>
    /// App.xaml 的交互逻辑
    /// </summary>
    public partial class App : Application
    {
        private readonly LogEngine _logEngine = new SonopostLogEngine();
        private readonly ManualResetEvent _manualResetEvent = new ManualResetEvent(false);

        private WebHost _webHost;
        private INetworkManager _networkManager;
        private IOledManager _oledManager;
        private bool _isWifi;
        private bool _isDisposed;

        protected override void OnStartup(StartupEventArgs e)
        {
            try
            {
                base.OnStartup(e);
                CheckedOpenRepeatedly();
                var absolutePath = Path.GetPathRoot(AppDomain.CurrentDomain.BaseDirectory);
                var path = Path.Combine(absolutePath, "Sonopost");
                DirectoryHelper.CreateDirectory(path);
                SonopostConstants.DataFolder = path;
                Logger.RegisterEngine(_logEngine);
                Logger.WriteLineWarn("=======================Sonopost BootUp=======================");
                FISIMPL.FISIMPL.InitLogWriter();
                var version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
                Logger.WriteLineInfo($"Current Version:{version}");
                AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException;
                this.DispatcherUnhandledException += OnDispatcherUnhandledException;
                SystemEvents.SessionEnded += OnSessionEnded;
                ProcessHelper.FinishProcessByName(SonopostConstants.UpgradeAppName);
                AppManager.Instance.Initialize();
                Init();
                CreateWebHost();
            }
            catch (Exception ex)
            {
                Logger.WriteLineError($"Sonopost Start Up Error:{ex}");
                SonopostUserDefinedSettings.Instance.Reset();
                Process.GetCurrentProcess().Kill();
            }
        }

        private void CreateWebHost()
        {
            if (_webHost == null)
            {
                _webHost = new WebHost();
                _webHost.Start();
            }
        }

        private void Init()
        {
            AppManager.Instance.GetManager<ILoginManager>().Init();
            AppManager.Instance.GetManager<IDeviceManager>().Init();
            AppManager.Instance.GetManager<ILiveVideoManager>().Init();
            SystemHelper.Init();
            _networkManager = AppManager.Instance.GetManager<INetworkManager>();
            _networkManager.CurrentNetworkChanged += OnCurrentNetworkChanged;
            _networkManager.CurrentWifiLevelChanged += OnCurrentWifiLevelChanged;
            _oledManager = AppManager.Instance.GetManager<IOledManager>();
            _oledManager.ShowStatus(OledMessage.Started);
            SetNetwork();
            OnCurrentNetworkChanged(null, _networkManager.CurrentNetwork);
            OnCurrentWifiLevelChanged(null, _networkManager.CurrentWifiLevel);
            // CheckAvailableDevices();
            AutoLogin();
            if (SonopostUserDefinedSettings.Instance.CaptureSetting.RealTimeCaptureEnabled)
            {
                AppManager.Instance.GetManager<IKeyBoardListenManager>().StartKeyBoardListen();
            }
        }

        private void OnCurrentNetworkChanged(object sender, NetworkInterfaceInfo e)
        {
            if (e != null)
            {
                var ip = e.IpAddress.Value;
                var mac = e.MacAddress;
                Logger.WriteLineInfo($"Current IP:{ip}");
                Logger.WriteLineInfo($"Current Mac:{mac}");
                if (!string.IsNullOrEmpty(ip) && e.OperationalStatus == OperationStatus.Connected)
                {
                    _oledManager.ShowMessages(1, MessageType.DisplayEnglishMediumWithPageNum, ip, 1);
                }
                else
                {
                    _oledManager.ShowMessages(1, MessageType.DisplayEnglishMediumWithPageNum, mac, 1);
                }
                _isWifi = e.NetworkInterfaceType == NetworkInterfaceType.Wireless80211;
                if (!_isWifi)
                {
                    _oledManager.ClearImage(1, 104, 4, 24, 24);
                }
            }
        }

        private void OnCurrentWifiLevelChanged(object sender, int e)
        {
            if (_isWifi)
            {
                var levelPic = $"wifi_{e}.png";
                _oledManager.ShowImage(1, MessageType.DisplayImageInCurrentPage, 104, 4, levelPic);
            }
        }

        private void SetNetwork()
        {
            try
            {
                if (SonopostUserDefinedSettings.Instance.NetworkSetting.NeedDoubleNetwork)
                {
                    var outsideAddress = SonopostUserDefinedSettings.Instance.NetworkSetting.OutsideNetworkMacAddress;

                    var outsideInterface = _networkManager.GetAllNetworkInterfaceInfos().FirstOrDefault(c => c.MacAddress == outsideAddress);

                    if (outsideInterface == null)
                        return;

                    var result = _networkManager.SetDualNetwork(outsideInterface.MacAddress);
                    Logger.WriteLineInfo(result ? "SetDualNetworkEnable Success!" : "SetDualNetworkEnable Fail!");
                }
            }
            catch (Exception e)
            {
                Logger.WriteLineError($"SetNetwork Error:{e}");
            }
        }

        private void AutoLogin()
        {
            Logger.WriteLineInfo($"Auto Login:{SonopostUserDefinedSettings.Instance.ServerSetting.IsAutoLogin}");
            if (SonopostUserDefinedSettings.Instance.ServerSetting.IsAutoLogin)
            {
                AppManager.Instance.GetManager<ILoginManager>().Login();
            }
        }

        private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
        {
            Logger.WriteLineError($"DispatcherUnhandledException:{e.Exception}");
            _oledManager?.ShowStatus(OledMessage.Error);
            Thread.Sleep(2000);
            Process.GetCurrentProcess().Kill();
        }

        private void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            Logger.WriteLineError($"UnhandledException:{e.ExceptionObject}");
            _oledManager?.ShowStatus(OledMessage.Error);
            Thread.Sleep(2000);
            Process.GetCurrentProcess().Kill();
        }

        /// <summary>
        /// 判断是否重复打开
        /// </summary>
        private void CheckedOpenRepeatedly()
        {
            var thisProcess = Process.GetCurrentProcess();
            if (Process.GetProcessesByName(thisProcess.ProcessName).Where(x => x.ProcessName == thisProcess.ProcessName).Count() > 1)
            {
                thisProcess.Kill();
            }
        }

        private void OnSessionEnded(object sender, SessionEndedEventArgs e)
        {
            try
            {
                Logger.WriteLineWarn($"Sonopost OnSessionEnded Invoke");
                Dispose();
            }
            catch (Exception ex)
            {
                Logger.WriteLineError($"Sonopost OnSessionEnded Invoke Error:{ex}");
            }
            finally
            {
                Process.GetCurrentProcess().Kill();
            }
        }

        protected override void OnExit(ExitEventArgs e)
        {
            try
            {
                Logger.WriteLineWarn("Sonopost OnExit Invoke");
                Dispose();
                base.OnExit(e);
            }
            catch (Exception ex)
            {
                Logger.WriteLineError($"Sonopost OnExit Invoke Error:{ex}");
            }
            finally
            {
                Process.GetCurrentProcess().Kill();
            }
        }

        private void Dispose()
        {
            if (_isDisposed)
            {
                _manualResetEvent.WaitOne(3000);
                return;
            }

            Logger.WriteLineWarn("Sonopost Dispose Invoke");
            try
            {
                _isDisposed = true;
                Task.Run(() =>
                {
                    try
                    {
                        _oledManager?.ShowStatus(OledMessage.ShutDown);
                        Thread.Sleep(50);
                        _networkManager.CurrentNetworkChanged -= OnCurrentNetworkChanged;
                        _networkManager.CurrentWifiLevelChanged -= OnCurrentWifiLevelChanged;
                        AppDomain.CurrentDomain.UnhandledException -= CurrentDomainUnhandledException;
                        SystemEvents.SessionEnded -= OnSessionEnded;
                        DisposeWebHost();
                        AppManager.Instance.DisposeAllManagers();
                        Logger.WriteLineWarn("=======================Sonopost Shutdown=======================");
                        _manualResetEvent.Set();
                    }
                    catch (Exception ex)
                    {
                        Logger.WriteLineError($"Sonopost Dispose Error:{ex}");
                    }
                });
                _manualResetEvent.WaitOne(3000);
            }
            catch (Exception ex)
            {
                Logger.WriteLineError($"Sonopost Dispose Error:{ex}");
            }
        }

        private void DisposeWebHost()
        {
            if (_webHost != null)
            {
                _webHost.Dispose();
                _webHost = null;
            }
        }
    }
}