using HuanMeng.DotNetCore.JwtInfrastructure.Interface;
using HuanMeng.DotNetCore.JwtInfrastructure;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text.Json;
using CloudGaming.Code.ExceptionExtend;
using Microsoft.AspNetCore.Http;
using SKIT.FlurlHttpClient.Wechat.TenpayV3.Models;

namespace CloudGaming.Code.AppExtend
{
    /// <summary>
    /// 
    /// </summary>
    public static class JwtTokenManageExtension
    {
        /// <summary>
        /// 添加jwt安全验证，配置
        /// </summary>
        /// <param name="server"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static void AddJwtConfig(this IHostApplicationBuilder builder)
        {
            var jwtTokenConfig = builder.Configuration.GetSection("JwtTokenConfig").Get<JwtTokenConfig>()!;
            if (jwtTokenConfig == null)
            {
                jwtTokenConfig = new JwtTokenConfig()
                {
                    Secret = Guid.NewGuid().ToString(),
                    AccessTokenExpiration = 60 * 60
                };
            }
            //注册一个jwtTokenConfig的单例服务
            builder.Services.AddSingleton(jwtTokenConfig);
            //
            builder.Services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(options =>
            {

                options.RequireHttpsMetadata = true;
                options.SaveToken = true;
                //调试使用
                //options.Events = new JwtDebugBearerEvents().GetJwtBearerEvents();
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    //是否验证颁发者
                    ValidateIssuer = true,
                    //是否验证受众
                    ValidateAudience = true,
                    //指定是否验证令牌的生存期。设置为 true 表示要进行验证。
                    ValidateLifetime = true,
                    //指定是否验证颁发者签名密钥。设置为 true 表示要进行验证。
                    ValidateIssuerSigningKey = true,
                    //颁发者
                    ValidIssuer = jwtTokenConfig.Issuer,
                    //受众
                    ValidAudience = jwtTokenConfig.Audience,
                    //指定用于验证颁发者签名的密钥
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtTokenConfig.Secret)),
                    //指定允许令牌的时钟偏移。允许令牌的过期时间与实际时间之间存在的时间差。在这里设置为 5 分钟，表示允许令牌的时钟偏移为 5 分钟。
                    ClockSkew = TimeSpan.FromMinutes(5)
                };
                options.Events = new JwtBearerEvents
                {
                    OnTokenValidated = async context =>
                    {

                        var token = context.Request.Headers.GetAuthorization();
                        if (string.IsNullOrEmpty(token))
                        {
                            context.Fail("非法请求接口");
                            return;
                        }
                        var _userId = context.Principal.FindFirst("userId")?.Value;
                        int userId = 0;
                        if (_userId == null || !int.TryParse(_userId, out userId))
                        {
                            context.Fail("请求标头错误");
                            return;
                        }
                        var tokenMd5 = MD5Encryption.ComputeMD5Hash(token);
                        var appConfig = context.HttpContext.RequestServices.GetRequiredService<AppConfig>();
                        var host = context.Request.Host.Host;
                        var app = AppConfigurationExtend.GetAppConfig(host);
                        app.ToAppConfig(appConfig);
                        if (app == null)
                        {
                            context.Fail("未配置租户");
                            return;
                        }
                        var redis = app.GetRedisDataBase();
                        var isUserExpire = await redis.StringGetAsync($"user:login:{_userId}:{tokenMd5}");

                        var isUserExpireStatus = isUserExpire.ToString();
                        if (string.IsNullOrEmpty(isUserExpireStatus))
                        {
                            //再次去数据库中验证
                            //IServiceProvider
                            //var _serviceProvider = context.HttpContext.RequestServices.GetRequiredService<IServiceProvider>();
                            var dao = context.HttpContext.RequestServices.GetDAO(app);
                            var c = await dao.DaoUser.Context.T_User_Token.CountAsync(it => it.UserId == userId && it.TokenMd5 == tokenMd5);
                            if (c <= 0)
                            {
                                //添加过期信息
                                await redis.StringSetAsync($"user:login:{_userId}:{tokenMd5}", "0", TimeSpan.FromMinutes(15));
                                //app.get
                                context.Fail(new LoginExpiredException(ResponseCode.LoginExpired, "用户状态错误"));
                                return;
                            }
                            else
                            {
                                isUserExpireStatus = "1";
                                //添加过期信息
                                await redis.StringSetAsync($"user:login:{_userId}:{tokenMd5}", "1", TimeSpan.FromMinutes(30));
                            }
                        }
                        if (isUserExpireStatus == "0")
                        {
                            //设备被顶掉
                            context.Fail(new LoginExpiredException(ResponseCode.LoginExpired, "用户在其它设备登录"));
                            return;
                        }

                    },
                    // 处理认证失败的事件
                    OnAuthenticationFailed = context =>
                    {
                        // 在这里可以根据需要设置自定义的HTTP状态码
                        context.Response.StatusCode = StatusCodes.Status403Forbidden; // 设置为 403 Forbidden
                        context.Response.ContentType = "application/json";
                        if (context.Exception is LoginExpiredException loginExpired)
                        {
                            //context.HttpContext.HandleResponse(); // 确保不再执行默认的挑战响应
                            context.Response.Clear(); // 清空现有响应内容
                            context.Response.StatusCode = StatusCodes.Status200OK; // 设置状态码为403 Forbidden
                            context.Response.ContentType = "application/json";
                            // 构建自定义的 JSON 响应
                            var str = loginExpired.ToString();
                            //var result = JsonSerializer.Serialize(new { error = context.AuthenticateFailure.Message });
                            return context.Response.WriteAsync(str); // 写入响应
                        }

                        //context.Response.Clear(); // 清空现有响应内容
                        //context.Response.StatusCode = StatusCodes.Status200OK; // 设置状态码为403 Forbidden

                        //// 返回自定义的错误消息
                        //var result = new BaseResponse<object>(ResponseCode.JwtError, "", null);
                        //return context.Response.WriteAsync(result.ToString());
                        return Task.CompletedTask;
                    },
                    // 在认证失败并被 Challenge 时触发该事件
                    OnChallenge = context =>
                    {

                        if (context.AuthenticateFailure is LoginExpiredException loginExpired)
                        {
                            context.HandleResponse(); // 确保不再执行默认的挑战响应
                            context.Response.Clear(); // 清空现有响应内容
                            context.Response.StatusCode = StatusCodes.Status200OK; // 设置状态码为403 Forbidden
                            context.Response.ContentType = "application/json";
                            // 构建自定义的 JSON 响应
                            var str = loginExpired.ToString();
                            //var result = JsonSerializer.Serialize(new { error = context.AuthenticateFailure.Message });
                            return context.Response.WriteAsync(str); // 写入响应
                        }
                        else
                        {
                            context.Response.Clear();
                        }
                        // 构建自定义的 JSON 响应
                        var result = new BaseResponse<object>(ResponseCode.UserNotLogin, "用户未登录", null);
                        // 如果已经有错误消息，则根据错误原因返回自定义状态码
                        if (context.AuthenticateFailure != null)
                        {
                            result.Message = context.AuthenticateFailure.Message;
                        }
                        context.HandleResponse(); // 确保不再执行默认的挑战响应
                        // 清空现有响应内容
                        context.Response.StatusCode = StatusCodes.Status200OK; // 设置状态码为403 Forbidden
                        context.Response.ContentType = "application/json";
                        return context.Response.WriteAsync(result.ToString()); // 写入响应

                        // 默认情况下返回 401 Unauthorized
                        //return Task.CompletedTask;
                    }
                };

            });
            //注册一个JwtAuthManager的单例服务
            builder.Services.AddSingleton<IJwtAuthManager, JwtManager>();
        }

    }
}
