using Furion;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Senparc.CO2NET;
using Senparc.CO2NET.AspNet;
using Senparc.Weixin;
using Senparc.Weixin.Cache.CsRedis;
using Senparc.Weixin.Entities;
using Senparc.Weixin.MP;
using Senparc.Weixin.Open;
using Senparc.Weixin.RegisterServices;
using Senparc.Weixin.WxOpen;
using Serilog;
using System;
using YBDevice.CommonService;
using YBDevice.Core;

namespace YBDevice.NApi.Core
{
    public class Startup : AppStartup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            var configuration = App.Configuration;
            services.AddHttpClient();
            services.AddRemoteRequest(options =>
            {
                //头条接口
                options.AddHttpClient("toutiao", c =>
                {
                    c.BaseAddress = new Uri("https://developer.toutiao.com/");
                });
            });
            services.AddCorsAccessor();
            //添加CAP
            services.AddCap(x =>
            {
                //配置rabbitmq支持
                string port = configuration["RabbitmqSetting:Port"];
                int p = Convert.ToInt32(port);
                x.UseRabbitMQ(opt =>
                {
                    opt.HostName = configuration["RabbitmqSetting:HostName"]; //配置ip地址
                    opt.Port = p;//配置端口
                    opt.UserName = configuration["RabbitmqSetting:UserName"];//配置用户名
                    opt.Password = configuration["RabbitmqSetting:Password"];//配置Miami
                });
                //配置sqlserver支持
                x.UseSqlServer(configuration["RabbitmqSetting:DBConnection"]);

                x.SucceedMessageExpiredAfter = 3600; //成功消息的过期时间,时间达到之后会删除,单位为秒
            });

            services.AddJwt<JwtHandler>(options =>
            {
                options.DefaultScheme = null;
            });
            services.AddControllersWithViews()
                   .AddInjectWithUnifyResult<RESTfulResultProvider>()
                 .AddNewtonsoftJson(options =>
                 {
                     options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; //日期格式化
                     options.SerializerSettings.ContractResolver = new CustomContractResolver();
                 });
            //如果部署在IIS上，需要加上下面的配置：
            services.Configure<IISServerOptions>(options => options.AllowSynchronousIO = true);

            #region 注入获取IP

            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            Nirvana.Common.MyHttpContext.serviceCollection = services;

            #endregion 注入获取IP

            //配置redis缓存
            services.AddStackExchangeRedisCache(options =>
            {
                options.Configuration = configuration["RedisServer"];
            });

            services.AddSenparcWeixinServices(configuration);//Senparc.Weixin 注册（必须）

            Senparc.Weixin.Config.ThrownWhenJsonResultFaild = false;
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
            IOptions<SenparcSetting> senparcSetting, IOptions<SenparcWeixinSetting> senparcWeixinSetting)
        {
            // 添加规范化结果状态码，需要在这里注册
            app.UseUnifyResultStatusCodes();
            //允许body重用
            app.Use(next => context =>
            {
                context.Request.EnableBuffering();
                return next(context);
            });
            //app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseSerilogRequestLogging(opts =>
            {
                opts.EnrichDiagnosticContext = LoggerHelper.EnrichFromRequest;
            });    // 必须在 UseStaticFiles 和 UseRouting 之间,记录请求日志
            app.UseRouting();
            app.UseCorsAccessor();

            #region 微信配置

            var registerService = app.UseSenparcGlobal(env, senparcSetting.Value, globalRegister =>
            {
                #region CO2NET 全局配置

                //配置全局使用Redis缓存（按需，独立）
                string redisConfigurationStr = UseRedis(senparcSetting.Value);
                /* 说明：
                 * 1、Redis 的连接字符串信息会从 Config.SenparcSetting.Cache_Redis_Configuration 自动获取并注册，如不需要修改，下方方法可以忽略
                /* 2、如需手动修改，可以通过下方 SetConfigurationOption 方法手动设置 Redis 链接信息（仅修改配置，不立即启用）
                 */
                Senparc.CO2NET.Cache.CsRedis.Register.SetConfigurationOption(redisConfigurationStr);

                //以下会立即将全局缓存设置为 Redis
                Senparc.CO2NET.Cache.CsRedis.Register.UseKeyValueRedisNow();//键值对缓存策略

                #endregion CO2NET 全局配置

                #region 注册日志（按需，建议）

                globalRegister.RegisterTraceLog(ConfigTraceLog);//配置TraceLog

                #endregion 注册日志（按需，建议）
            }, true)
             .UseSenparcWeixin(senparcWeixinSetting.Value, (weixinRegister, _) =>
             {
                 var _wxservice = App.GetService<IWXService>();

                 App.GetService<ILoggerFactory>().CreateLogger("senparcWeixin").LogInformation($"senparcWeixinSetting:IsDebug:{senparcWeixinSetting.Value.IsDebug}");

                 #region 微信缓存（按需，必须放在配置开头，以确保其他可能依赖到缓存的注册过程使用正确的配置）

                 //注意：如果使用非本地缓存，而不执行本块注册代码，将会收到“当前扩展缓存策略没有进行注册”的异常
                 //微信的 Redis 缓存，如果不使用则注释掉（开启前必须保证配置有效，否则会抛错）
                 weixinRegister.UseSenparcWeixinCacheCsRedis();//CsRedis
                 weixinRegister

                 #endregion 微信缓存（按需，必须放在配置开头，以确保其他可能依赖到缓存的注册过程使用正确的配置）

                 #region 注册公众号

                .RegisterMpAccount(senparcWeixinSetting.Value)// DPBMARK_END

                 #endregion 注册公众号

                 #region 注册小程序

                 #region 商户端

                .RegisterWxOpenAccount(senparcWeixinSetting.Value)
                .RegisterWxOpenAccount(senparcWeixinSetting.Value.Items["lxbusinessclient"], "lxbusinessclient")
                .RegisterWxOpenAccount(senparcWeixinSetting.Value.Items["xcjbusinessclient"], "xcjbusinessclient")
                .RegisterWxOpenAccount(senparcWeixinSetting.Value.Items["abbusinessclient"], "abbusinessclient")

                 #endregion 商户端

                 #region 儿童单机版测量小程序

                .RegisterWxOpenAccount(senparcWeixinSetting.Value.Items["childresultclient"], "childresultclient")

                 #endregion 儿童单机版测量小程序

                 #endregion 注册小程序

                 #region 注册开放平台

                 .RegisterOpenComponent(senparcWeixinSetting.Value,
                 //getComponentVerifyTicketFunc
                 async componentAppId =>
                 {
                     var component = await _wxservice.GetOpenTicketAsync(componentAppId);
                     return component;
                 },
                 //getAuthorizerRefreshTokenFunc
                 async (componentAppId, auhtorizerId) =>
                 {
                     return await _wxservice.GetRefreshToken(auhtorizerId, componentAppId);
                 },
                  //authorizerTokenRefreshedFunc
                  (componentAppId, auhtorizerId, refreshResult) =>
                  {
                  })

                 #endregion 注册开放平台

                  ;
             });

            #endregion 微信配置

            app.UseAuthentication();
            app.UseAuthorization();
            app.UseInject();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
        }

        /// <summary>
        /// 配置微信跟踪日志（演示，按需）
        /// </summary>
        private void ConfigTraceLog()
        {
            //这里设为Debug状态时，/App_Data/WeixinTraceLog/目录下会生成日志文件记录所有的API请求日志，正式发布版本建议关闭

            //如果全局的IsDebug（Senparc.CO2NET.Config.IsDebug）为false，此处可以单独设置true，否则自动为true
            Senparc.CO2NET.Trace.SenparcTrace.SendCustomLog("系统日志", "系统启动");//只在Senparc.Weixin.Config.IsDebug = true的情况下生效

            //全局自定义日志记录回调
            Senparc.CO2NET.Trace.SenparcTrace.OnLogFunc = () =>
            {
            };

            //当发生基于WeixinException的异常时触发
            WeixinTrace.OnWeixinExceptionFunc = ex =>
            {
                //加入每次触发WeixinExceptionLog后需要执行的代码

                //发送模板消息给管理员                                   -- DPBMARK Redis
                var eventService = new EventService();
                eventService.ConfigOnWeixinExceptionFunc(ex);      // DPBMARK_END
            };
        }

        /// <summary>
        /// 判断当前配置是否满足使用 Redis（根据是否已经修改了默认配置字符串判断）
        /// </summary>
        /// <param name="senparcSetting"></param>
        /// <returns></returns>
        private string UseRedis(SenparcSetting senparcSetting)
        {
            string redisConfigurationStr = senparcSetting.Cache_Redis_Configuration;
            return redisConfigurationStr;
        }
    }
}