using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Prism.Ioc;
using Prism.Modularity;
using Prism.Unity;
using Rdh.ElectronicMedicineKit.EntityFrameworkCore;
using Rdh.SocketServer.Client.BLL;
using Rdh.SocketServer.Client.Models;
using Rdh.SocketServer.Client.MQ;
using Rdh.SocketServer.Client.Views;
using Serilog;
using Serilog.Formatting.Compact;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using TouchSocket.Core.Config;
using TouchSocket.Core.Dependency;
using TouchSocket.Core.Plugins;
using TouchSocket.Sockets;
using Unity;
using Unity.Microsoft.DependencyInjection;

namespace Rdh.SocketServer.Client
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : PrismApplication
    {
        public App()
        {
        }

        protected override void OnStartup(StartupEventArgs e)
        {
            //限制程序单实例运行
            if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1)
            {
                Application.Current.Shutdown();
                return;
            }
            RegisterEvents();
            base.OnStartup(e);
        }

        protected override Window CreateShell()
        {
            return Container.Resolve<MainWindowView>();
        }

        protected override void OnInitialized()
        {
            base.OnInitialized();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            //containerRegistry.RegisterForNavigation<MainWindowView>();
        }

        protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
        {

        }

        protected override IContainerExtension CreateContainerExtension()
        {
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            // 配置日志文件
            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .Enrich.FromLogContext()
                .WriteTo.Async(c => c.File(
                    new CompactJsonFormatter(),
                    path: Environment.GetEnvironmentVariable("RDH_LOG_PATH") ?? "logs//Log.txt",
                    rollingInterval: RollingInterval.Day,
                    retainedFileCountLimit: 60))
#if DEBUG
                    .WriteTo.Console()
#endif
                .CreateLogger();
            Log.Information("Starting Rdh.SocketServer Client.");

            // 实例化Services集合
            var services = new ServiceCollection();

            // 加载配置文件
            var config = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", false, true)
            .Build();
            // 注册配置文件服务
            services.AddSingleton<IConfiguration>(config);
            //注册日志文件服务
            services.AddLogging(option => option.AddSerilog());

            var connectionStrings = config.GetSection("DataBaseConnectStrings").Get<List<DataBaseConnectString>>();
            services.AddDbContext<ApplicationDbContext>(options =>
            {
                options.UseSqlite(connectionStrings.First(x => x.DbType == DbTypes.Sqlite).ConnectionString, b => b.MigrationsAssembly("Rdh.SocketServer.Client"));
                options.UseLazyLoadingProxies();
                options.EnableSensitiveDataLogging();
            });
            ShouShuShiUtility.ConnectionString = connectionStrings.FirstOrDefault(x => x.Name == "ShouShuShi")?.ConnectionString;
            Serilog.Log.Debug("设置手术室数据库：" + ShouShuShiUtility.ConnectionString);
            MQService.Singleton.EleMedKitCabinetNodeName = config.GetSection("EleMedKitCabinetMQNodeName")?.Value;
            String? state = MQService.Singleton.Init();
            Log.Information("初始化MQservice：" + (state == null ? "ok" : state));
            #region MyRegion
            //connectionStrings.ForEach(conn =>
            //{
            //    switch (conn.Name)
            //    {
            //        default:
            //            services.AddDbContext<ApplicationDbContext>(options =>
            //            {
            //                switch (conn.DbType)
            //                {
            //                    case DbTypes.Oracle:
            //                        break;
            //                    case DbTypes.Mysql:
            //                        //options.UseMySQL(conn.ConnectionString/*, b => b.MigrationsAssembly("Rdh.HempCart.WebApi")*/);
            //                        break;
            //                    case DbTypes.SQLServer:
            //                        break;
            //                    case DbTypes.Sqlite:
            //                        break;
            //                    default:
            //                        break;
            //                }
            //            });
            //            break;
            //    }
            //}); 
            #endregion


            // 读取TcpService服务列表 并注册配置相应服务
            var tcpServices = config.GetSection("TcpServers").Get<List<TcpServiceInfo>>();
            if (tcpServices.Any())
            {
                tcpServices.ForEach(info =>
                {
                    var service = new TcpService();
                    service.Setup(new TouchSocketConfig()//载入配置     
                        .SetListenIPHosts(new IPHost[] { new IPHost(info.Port) })
                        .SetMaxCount(10000)
                        .SetThreadCount(10)
                        .SetServerName(info.ServerName)
                        .ConfigurePlugins(a => a.UseReconnection(5, true, 1000)))
                    .Start();

                    if (info.ServerName == "ElectronicMedicineKit")
                        service.Config.SetDataHandlingAdapter(() => new EleMedKitServerAdapter());
                    services.AddSingleton<ITcpService>(service);
                });
            }


            // 实例化Unity Ioc容器
            var container = new UnityContainer();
            // 将服务集合注册进容器
            container.BuildServiceProvider(services);
            return new UnityContainerExtension(container);
        }
        #region 日志相关

        private void RegisterEvents()
        {
            TaskScheduler.UnobservedTaskException += this.TaskScheduler_UnobservedTaskException;
            DispatcherUnhandledException += App_DispatcherUnhandledException;
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
        }

        /// <summary>
        /// Task线程内未捕获异常处理事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskScheduler_UnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
        {
            try
            {
                if (e.Exception is Exception exception)
                {
                    HandleException(exception);
                }
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }
            finally
            {
                e.SetObserved();
            }
        }


        /// <summary>
        /// 非UI线程未捕获异常处理事件(例如自己创建的一个子线程)     
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            try
            {
                if (e.ExceptionObject is Exception exception)
                {
                    HandleException(exception);
                }
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }
            finally
            {
                //ignore
            }
        }

        /// <summary>
        /// UI线程未捕获异常处理事件（UI主线程）
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            try
            {
                HandleException(e.Exception);
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }
            finally
            {
                e.Handled = true;
            }
        }

        /// <summary>
        /// 日志记录
        /// </summary>
        /// <param name="ex"></param>
        private void HandleException(Exception ex)
        {
            Log.Error(ex, ex.Message);
        }
        #endregion
    }
}
