using System;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Configuration;
using Serilog;
using System.Threading.Tasks;
using MassTransit;
using MassTransit.NewIdProviders;
using System.IO;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Application.Helper;
using System.Runtime.InteropServices;
using Microsoft.AspNetCore.Builder;
using IRaCIS.Core.API;
using Autofac;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
using IRaCIS.Core.Application.Filter;
using Microsoft.AspNetCore.HttpOverrides;
using IRaCIS.Core.Application.Service.BackGroundJob;
using LogDashboard;
using FellowOakDicom.Network;
using IRaCIS.Core.Application.Service.ImageAndDoc;
using IP2Region.Net.Abstractions;
using IP2Region.Net.XDB;
using IRaCIS.Core.Application.BusinessFilter;
using Microsoft.AspNetCore.Http;
using IRaCIS.Core.Infrastructure.Extention;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Diagnostics;
using IRaCIS.Core.Application.MassTransit.Command;
using IRaCIS.Core.Application.MassTransit.Consumer;
using DocumentFormat.OpenXml.InkML;
using IRaCIS.Core.Domain;

AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
#region 获取环境变量
//以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
var config = new ConfigurationBuilder()
            .AddEnvironmentVariables()
            .Build();

var enviromentName = config["ASPNETCORE_ENVIRONMENT"];

if (string.IsNullOrWhiteSpace(enviromentName))
{

    var index = Array.IndexOf(args, "--env");
    enviromentName = index > -1
        ? args[index + 1]
        : "Development";
}
#endregion

var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    EnvironmentName = enviromentName
});

#region 兼容windows 服务命令行的方式

//foreach (var arg in args)
//{
//    Console.WriteLine(arg);
//}

int urlsIndex = Array.FindIndex(args, arg => arg != null && arg.StartsWith("--urls"));

if (urlsIndex > -1)
{
    var url = args[urlsIndex].Substring("--urls=".Length);
    Console.WriteLine(url);
    builder.WebHost.UseUrls(url);
}

#endregion

#region 主机配置


NewId.SetProcessIdProvider(new CurrentProcessIdProvider());

builder.Configuration.AddJsonFile(ConfigMapFileProvider.FromRelativePath(""), "appsettings.json", false, true)
                     .AddJsonFile(ConfigMapFileProvider.FromRelativePath(""), $"appsettings.{enviromentName}.json", false, true);

builder.Host
            .UseServiceProviderFactory(new AutofacServiceProviderFactory())
            .ConfigureContainer<ContainerBuilder>(containerBuilder =>
            {
                containerBuilder.RegisterModule<AutofacModuleSetup>();
            })
            .UseWindowsService().UseSerilog();
#endregion


#region 配置服务
var _configuration = builder.Configuration;

//健康检查
builder.Services.AddHealthChecks();
//本地化
builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resources");

// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
builder.Services.AddControllers(options =>
{
    //options.Filters.Add<LogActionFilter>();
    options.Filters.Add<ModelActionFilter>();
    options.Filters.Add<ProjectExceptionFilter>();
    options.Filters.Add<UnitOfWorkFilter>();
    //options.Filters.Add<EncreptApiResultFilter>(10);
    options.Filters.Add<LimitUserRequestAuthorization>();


})
    .AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化  处理

builder.Services.AddOptions().Configure<SystemEmailSendConfig>(_configuration.GetSection("SystemEmailSendConfig"));
builder.Services.AddOptions().Configure<ServiceVerifyConfigOption>(_configuration.GetSection("BasicSystemConfig"));
builder.Services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
builder.Services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
builder.Services.AddOptions().Configure<IRCEncreptOption>(_configuration.GetSection("EncrypteResponseConfig"));
builder.Services.AddOptions().Configure<SystemPacsConfig>(_configuration.GetSection("SystemPacsConfig"));

builder.Services.Configure<IRaCISBasicConfigOption>(_configuration.GetSection("IRaCISBasicConfig"));


//动态WebApi + UnifiedApiResultFilter  省掉控制器代码
builder.Services.AddDynamicWebApiSetup();
//AutoMapper
builder.Services.AddAutoMapperSetup();
//EF ORM  QueryWithNoLock
builder.Services.AddEFSetup(_configuration,enviromentName);
//Http 响应压缩
builder.Services.AddResponseCompressionSetup();
//Swagger Api 文档
builder.Services.AddSwaggerSetup();
//JWT Token 验证
builder.Services.AddJWTAuthSetup(_configuration);

// MediatR 进程内消息 事件解耦  从程序集中 注册命令和handler对应关系
//builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<ConsistencyVerificationHandler>());

#region MassTransit
//masstransit组件 也支持MediatR 中介者模式,但是支持分布式,考虑后续,所以在次替代MediatR
builder.Services.AddMediator(cfg =>
{
    cfg.AddConsumer<ConsistencyCheckConsumer>();
    cfg.AddConsumer<AddUserLogTriggerConsumer>();
    cfg.AddConsumer<AddSubjectTriggerConsumer>();
});

// 添加 MassTransit 和 InMemory 传输
builder.Services.AddMassTransit(cfg =>
{
    // 注册消费者
    //cfg.AddConsumer<AddSubjectTriggerConsumer>(); // 替换为你的消费者类

    // 使用 InMemory 作为消息传递机制
    cfg.UsingInMemory((context, cfg) =>
    {
        // 这里可以进行额外的配置
        cfg.ConfigureEndpoints(context); // 自动配置所有消费者的端点
    });


});
#endregion


#region FusionCache

builder.Services.AddFusionCache();

#endregion

// EasyCaching 缓存
//builder.Services.AddEasyCachingSetup(_configuration);

// hangfire  定时任务框架  有界面,更友好~
builder.Services.AddhangfireSetup(_configuration);


//Serilog 日志可视化 LogDashboard日志
builder.Services.AddLogDashboardSetup();


builder.Services.AddJsonConfigSetup(_configuration);
//转发头设置  获取真实IP 
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
//Dicom影像渲染图片  跨平台
builder.Services.AddDicomSetup();

// 实时应用
builder.Services.AddSignalR();

builder.Services.AddSingleton<IUserIdProvider, IRaCISUserIdProvider>();


builder.Services.AddSingleton<ISearcher>(new Searcher(CachePolicy.Content, Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources, "ip2region.xdb")));

//builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
//builder.Services.AddProblemDetails();

#region  历史废弃配置
//builder.Services.AddMemoryCache();
////上传限制 配置
//builder.Services.Configure<FormOptions>(options =>
//{
//    options.MultipartBodyLengthLimit = int.MaxValue;
//    options.ValueCountLimit = int.MaxValue;
//    options.ValueLengthLimit = int.MaxValue;
//});
//IP 限流 可设置白名单 或者黑名单
//services.AddIpPolicyRateLimitSetup(_configuration);
// 用户类型 策略授权
//services.AddAuthorizationPolicySetup(_configuration);
#endregion

#endregion

var app = builder.Build();
var env = app.Environment;

#region 配置中间件

app.UseMiddleware<EncryptionRequestMiddleware>();

// Configure the HTTP request pipeline.

#region 异常处理  全局业务异常已统一处理了,非业务错误会来到这里  400 -500状态码


//app.UseStatusCodePagesWithReExecute("/Error/{0}");

app.UseStatusCodePages(async context =>
{
    var code = context.HttpContext.Response.StatusCode;
    context.HttpContext.Response.ContentType = "application/json";
    if (code < 500)
    {
        await context.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk($"Client error, actual request error status code({code})")));
    }
    else
    {
        //ResultFilter 里面的异常并不会到这里
        await context.HttpContext.Response.WriteAsync(JsonConvert.SerializeObject((ResponseOutput.NotOk($"Server error , actual request error status code({code})"))));
    }

});

//app.UseExceptionHandler(o => { });

//这里没生效,原因未知,官方文档也是这种写法,也用了GlobalExceptionHandler 尝试,还是不行,怀疑框架bug
//app.UseExceptionHandler(configure =>
//{
//    configure.Run(async context =>
//    {
//        var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>();
//var ex = exceptionHandlerPathFeature?.Error;
//context.Response.ContentType = "application/json";

//if (ex != null)
//{
//    var errorInfo = $"Exception: {ex.Message}[{ex.StackTrace}]" + (ex.InnerException != null ? $" InnerException: {ex.InnerException.Message}[{ex.InnerException.StackTrace}]" : "");

//    await context.Response.WriteAsync(JsonConvert.SerializeObject(ResponseOutput.NotOk($"{ex?.Message}")));

//    Log.Logger.Error(errorInfo);


//}

//    });
//});



#endregion

//本地化
app.UseLocalization();

app.UseForwardedHeaders();

//响应压缩
app.UseResponseCompression();


//不需要 token 访问的静态文件  wwwroot css, JavaScript, and images don't require authentication.
app.UseStaticFiles();



//LogDashboard
app.UseLogDashboard("/LogDashboard");

//hangfire
app.UseHangfireConfig(env);

#region 暂时废弃

//app.UseMiddleware<MultiDiskStaticFilesMiddleware>();
////限流 中间件
//app.UseIpRateLimiting();
//if (env.IsDevelopment())
//{
//    app.UseDeveloperExceptionPage();
//}
//else
//{
//    //app.UseHsts();
//}
#endregion





SwaggerSetup.Configure(app, env);


////serilog 记录请求的用户信息
app.UseSerilogConfig(env);

app.UseRouting();

app.UseCors(t => t.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());

//app.UseIRacisHostStaticFileStore(env);


app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.MapHub<UploadHub>("/UploadHub");
app.MapHealthChecks("/health");


// Serilog 
SerilogExtension.AddSerilogSetup(enviromentName, app.Services);


var hangfireJobService = app.Services.GetRequiredService<IIRaCISHangfireJob>();

await hangfireJobService.InitHangfireJobTaskAsync();



#endregion

try
{
    #region 运行环境 部署平台

    Log.Logger.Warning($"当前环境:{enviromentName}");

    if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
    {
        Log.Logger.Warning($"当前部署平台环境:windows");
    }
    else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
    {
        Log.Logger.Warning($"当前部署平台环境:linux");
    }
    else
    {
        Log.Logger.Warning($"当前部署平台环境:OSX  or FreeBSD");
    }

    #endregion


    Log.Logger.Warning($"ContentRootPath:{env.ContentRootPath}");


    string parentDirectory = Path.GetFullPath(Path.Combine(env.ContentRootPath, ".."));


    Log.Logger.Warning($"ContentRootPath——parentDirectory:{parentDirectory}");

    //Log.Logger.Warning($"ContentRootPath——GetParent:{Directory.GetParent(env.ContentRootPath).Parent.FullName}");
    //Log.Logger.Warning($"ContentRootPath——xx:{Path.GetDirectoryName(Path.GetDirectoryName(env.ContentRootPath))}");


    app.Run();

}
catch (Exception e)
{

    Log.Logger.Error(e.InnerException is null ? e.Message + e.StackTrace : e.InnerException?.Message + e.InnerException?.StackTrace);
}