using IdentityModel.Client;
using IRaCIS.Core.Application.Service.OAuth;
using MassTransit;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;

namespace IRaCIS.Core.Application.Service
{
    public class OAuthService : ServiceBase
    {



        #region authorization_code 原生  PKCE 

        public IResponseOutput TestPCKEOrgin()
        {
            // 1. 生成 code_verifier 和 code_challenge
            string codeVerifier = "QMSBBxTQrpKPscvNNfmaQfmyk5Wd33GZS1FKSo3Shv8w-59vW1iTSlgAznYojkYv2DgR4XhTqySsBnDPq0";


            string codeChallenge = PkceUtil.GenerateCodeChallenge(codeVerifier);

            Console.WriteLine(codeVerifier);

            string clientId = "aj34vqrpvz8olsbxwtcog";
            string redirectUri = "http://localhost:6100/OAuth/TestPKCECallBack";
            string state = "123456";

            // 构造请求的 URL
            string authorizationUrl = $"https://logto.test.extimaging.com/oidc/auth" +
                $"?client_id={clientId}" +
                $"&redirect_uri={Uri.EscapeDataString(redirectUri)}" +
                $"&response_type=code" +
                $"&scope=openid profile email phone" +
                $"&code_challenge={codeChallenge}" +
                $"&code_challenge_method=S256" +
                $"&state={state}";

            Console.WriteLine("请将以下 URL 复制到浏览器中，完成登录后获取 code:");

            Console.WriteLine(authorizationUrl);

            return ResponseOutput.Ok();

        }


        [AllowAnonymous]
        [RoutePattern(HttpMethod = "Get")]
        public async Task<IResponseOutput> TestPKCECallBackAsync(string code)
        {
            var httpClient = new HttpClient();
            var disco = await httpClient.GetDiscoveryDocumentAsync("https://logto.test.extimaging.com/oidc");
            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
            }

            string codeVerifier = "QMSBBxTQrpKPscvNNfmaQfmyk5Wd33GZS1FKSo3Shv8w-59vW1iTSlgAznYojkYv2DgR4XhTqySsBnDPq0";
            // OIDC 配置，替换为您的 OIDC 提供者的配置
            string tokenEndpoint = "https://logto.test.extimaging.com/oidc/token"; // 替换为实际 token 端点
            string clientId = "aj34vqrpvz8olsbxwtcog";
            string redirectUri = "http://localhost:6100/OAuth/TestPKCECallBack"; // 替换为前端的回调 URL

            var baseUrl = "https://logto.test.extimaging.com";
            var opts = new RestClientOptions(baseUrl);
            using var client = new RestClient(opts);

            //https://blog.logto.io/troubleshoot-invalid-grant-error/
            var request = new RestRequest("oidc/token", Method.Post)
            .AddHeader("Content-Type", "application/x-www-form-urlencoded");

            request.AddParameter("grant_type", "authorization_code")
                    .AddParameter("code", code)
                    .AddParameter("redirect_uri", redirectUri)
                    .AddParameter("client_id", clientId)
                    .AddParameter("code_verifier", codeVerifier); // 使用 PKCE


            // 发送请求并获取响应
            var response = await client.ExecuteAsync<LogtoTokenResponse>(request);

            if (response.StatusCode == HttpStatusCode.OK)
            {
                var tokenResponse = response.Data;

                Console.WriteLine(tokenResponse.ToJsonStr());

                var userInfoRequest = new RestRequest($"oidc/me", Method.Get)
                    .AddHeader("Authorization", $"Bearer {tokenResponse.AccessToken}");

                var userResponse = await client.ExecuteAsync(userInfoRequest);

                Console.WriteLine(userResponse.Content);

                //结束回话

                var endUrl = new RequestUrl(disco.EndSessionEndpoint).CreateEndSessionUrl(tokenResponse.IdToken, "http://localhost:6100/OAuth/TestPCKEOrgin");

                var _endHttpClient = new HttpClient();

                var dd = await _endHttpClient.GetAsync(endUrl);
            }

            return ResponseOutput.Ok();
        }
        #endregion


        #region authorization_code OidcClient  PKCE 

        [AllowAnonymous]
        [RoutePattern(HttpMethod = "Get")]
        public IResponseOutput TestPKCE()
        {
            // 1. 生成 code_verifier 和 code_challenge
            string codeVerifier = "QMSBBxTQrpKPscvNNfmaQfmyk5Wd33GZS1FKSo3Shv8w-59vW1iTSlgAznYojkYv2DgR4XhTqySsBnDPq0";


            string codeChallenge = PkceUtil.GenerateCodeChallenge(codeVerifier);

            Console.WriteLine(codeVerifier);

            string clientId = "aj34vqrpvz8olsbxwtcog";
            string redirectUri = "http://localhost:6100/OAuth/TestOidcClientPKCECallBack";
            string state = "123456";

            // 构造请求的 URL
            string authorizationUrl = $"https://logto.test.extimaging.com/oidc/auth" +
                $"?client_id={clientId}" +
                $"&redirect_uri={Uri.EscapeDataString(redirectUri)}" +
                $"&response_type=code" +
                $"&scope=openid profile email phone" +
                $"&code_challenge={codeChallenge}" +
                $"&code_challenge_method=S256" +
                $"&state={state}";

            Console.WriteLine("请将以下 URL 复制到浏览器中，完成登录后获取 code:");

            Console.WriteLine(authorizationUrl);

            return ResponseOutput.Ok();

        }

        [AllowAnonymous]
        [RoutePattern(HttpMethod = "Get")]
        public async Task<IResponseOutput> TestOidcClientPKCECallBackAsync(string code)
        {
            //使用IdentityModel.OidcClient 测试
            var client = new HttpClient();
            var disco = await client.GetDiscoveryDocumentAsync("https://logto.test.extimaging.com/oidc");
            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
            }

            // OIDC 配置，替换为您的 OIDC 提供者的配置
            string clientId = "aj34vqrpvz8olsbxwtcog";
            string codeVerifier = "QMSBBxTQrpKPscvNNfmaQfmyk5Wd33GZS1FKSo3Shv8w-59vW1iTSlgAznYojkYv2DgR4XhTqySsBnDPq0";
            string redirectUri = "http://localhost:6100/OAuth/TestOidcClientPKCECallBack"; // 替换为前端的回调 URL

            var requestBody = new Dictionary<string, string>
                                {
                                    { "grant_type", "authorization_code" },
                                    { "code", code },
                                    { "redirect_uri", redirectUri },
                                    { "client_id", clientId },
                                    { "code_verifier", codeVerifier } // 使用 PKCE
                                };

            var _httpClient = new HttpClient();
            var content = new FormUrlEncodedContent(requestBody);
            // 发出 token 请求
            var response = await _httpClient.PostAsync(disco.TokenEndpoint, content);


            if (response.IsSuccessStatusCode)
            {
                var responseBody = await response.Content.ReadAsStringAsync();

                // 解析 JSON
                var jsonObject = JObject.Parse(responseBody);

                // 格式化并输出 JSON
                var formattedJson = jsonObject.ToString(Formatting.Indented);

                Console.WriteLine(formattedJson);

                var tokenResponse = JsonConvert.DeserializeObject<LogtoTokenResponse>(responseBody);

                Console.WriteLine(tokenResponse);

                //结束回话
                var parameters = new Parameters();

                parameters.Add("clientId", "aj34vqrpvz8olsbxwtcog");
                var endUrl = new RequestUrl(disco.EndSessionEndpoint).CreateEndSessionUrl(tokenResponse.IdToken, "http://localhost:6100/OAuth/TestPCKEOrgin", extra: parameters);

              
                Results.Redirect(endUrl);
                //var _endHttpClient = new HttpClient();

                //var dd = await _endHttpClient.GetAsync(endUrl);

            }
            else
            {
                var errorContent = await response.Content.ReadAsStringAsync();
                throw new Exception($"Error: {errorContent}");
            }

            #region 提示必须要Secret
            //// 准备请求内容
            //var tokenRequest = new AuthorizationCodeTokenRequest
            //{
            //    Address = disco.TokenEndpoint,
            //    ClientId = clientId,
            //    Code = code,
            //    RedirectUri = redirectUri,
            //    GrantType = "authorization_code",
            //    CodeVerifier = codeVerifier

            //};

            //var tokenResponse = await _httpClient.RequestTokenAsync(tokenRequest);

            //if (tokenResponse.HttpStatusCode == HttpStatusCode.OK)
            //{
            //    var apiClient = new HttpClient();
            //    apiClient.SetBearerToken(tokenResponse.AccessToken);

            //    var response = await apiClient.GetAsync(disco.UserInfoEndpoint);
            //    if (!response.IsSuccessStatusCode)
            //    {
            //        Console.WriteLine(response.StatusCode);
            //        Console.WriteLine(response.ReasonPhrase);
            //    }
            //    else
            //    {
            //        var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync()).RootElement;
            //        Console.WriteLine(JsonSerializer.Serialize(doc, new JsonSerializerOptions { WriteIndented = true }));

            //        //获取刷新token 
            //        var refreshClient = new HttpClient();
            //        var refreshRequest = new RefreshTokenRequest
            //        {
            //            Address = disco.TokenEndpoint,
            //            ClientId = clientId,
            //            RefreshToken = tokenResponse.RefreshToken,
            //        };

            //        var refreshResponse = await refreshClient.RequestRefreshTokenAsync(refreshRequest);

            //        if (refreshResponse.IsError)
            //        {
            //            Console.WriteLine($"Error: {refreshResponse.Error}");
            //        }
            //        else
            //        {
            //            Console.WriteLine("获取刷新token 完成");

            //            Console.WriteLine("AccessToken:" + refreshResponse.AccessToken);

            //            Console.WriteLine("RefreshToken:" + refreshResponse.RefreshToken);
            //        }

            //    }
            //}
            #endregion




            return ResponseOutput.Ok();
        }


        #endregion


        #region OIDC  authorization_code  with  client_secret

        [AllowAnonymous]
        public IResponseOutput TestOidcClientWithSecret()
        {

            string clientId = "tl42rjin7obxtwqqgvkti";
            string redirectUri = "http://localhost:6100/OAuth/TestOidcClientCallBack";
            string state = "123456";

            // 构造请求的 URL
            string authorizationUrl = $"https://logto.test.extimaging.com/oidc/auth" +
                $"?client_id={clientId}" +
                $"&redirect_uri={Uri.EscapeDataString(redirectUri)}" +
                $"&response_type=code" +
                $"&scope=openid profile email phone" +
                $"&state={state}";

            Console.WriteLine(authorizationUrl);

            return ResponseOutput.Ok();

        }



        [AllowAnonymous]
        [RoutePattern(HttpMethod = "Get")]
        public async Task<IResponseOutput> TestOidcClientCallBackAsync(string code)
        {
            //使用IdentityModel.OidcClient 测试
            var client = new HttpClient();
            var disco = await client.GetDiscoveryDocumentAsync("https://logto.test.extimaging.com/oidc");
            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
            }

            // OIDC 配置，替换为您的 OIDC 提供者的配置
            string clientId = "tl42rjin7obxtwqqgvkti";
            string clientSecret = "Pu9ig4rz44aLlxb0yKUaOiZaFk6Bcu51";
            string redirectUri = "http://localhost:6100/OAuth/TestOidcClientCallBack"; // 替换为前端的回调 URL
            string postLogoutRedirectUri = "http://localhost:6100/OAuth/TestPCKEOrgin"; //退出回话重定向到前端的url
            // 准备请求内容
            var tokenRequest = new AuthorizationCodeTokenRequest
            {
                Address = disco.TokenEndpoint,
                ClientId = clientId,
                ClientSecret = clientSecret,
                Code = code,
                RedirectUri = redirectUri,
                GrantType = "authorization_code",

            };

            var _httpClient = new HttpClient();
            // 发出 token 请求
            var tokenResponse = await _httpClient.RequestAuthorizationCodeTokenAsync(tokenRequest);


            if (tokenResponse.HttpStatusCode == HttpStatusCode.OK)
            {
                var apiClient = new HttpClient();
                apiClient.SetBearerToken(tokenResponse.AccessToken);

                var response = await apiClient.GetAsync(disco.UserInfoEndpoint);
                if (!response.IsSuccessStatusCode)
                {
                    Console.WriteLine(response.StatusCode);
                    Console.WriteLine(response.ReasonPhrase);
                }
                else
                {
                    var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync()).RootElement;
                    Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(doc, new JsonSerializerOptions { WriteIndented = true }));

                    //获取刷新token 
                    var refreshClient = new HttpClient();
                    var refreshRequest = new RefreshTokenRequest
                    {
                        Address = disco.TokenEndpoint,
                        ClientId = clientId,
                        ClientSecret = clientSecret,
                        RefreshToken = tokenResponse.RefreshToken,
                    };

                    var refreshResponse = await refreshClient.RequestRefreshTokenAsync(refreshRequest);

                    if (refreshResponse.IsError)
                    {
                        Console.WriteLine($"Error: {refreshResponse.Error}");
                    }
                    else
                    {
                        Console.WriteLine("获取刷新token 完成");

                        Console.WriteLine("AccessToken:" + refreshResponse.AccessToken);

                        Console.WriteLine("RefreshToken:" + refreshResponse.RefreshToken);
                    }



                }
            }

            return ResponseOutput.Ok();
        }

        #endregion


        #region 客户端凭证

        /// <summary>
        /// 测试客户端凭证代码
        /// </summary>
        /// <returns></returns>
        public async Task<IResponseOutput> TestClientCredentialsAsync()
        {

            #region 使用IdentityModel.OidcClient 测试

            // discover endpoints from metadata
            var client = new HttpClient();

            var disco = await client.GetDiscoveryDocumentAsync("https://logto.test.extimaging.com/oidc");
            if (disco.IsError)
            {
                Console.WriteLine(disco.Error);
            }

            // request token
            var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
            {
                Address = disco.TokenEndpoint,
                ClientId = "v2mr2ndxwkxz0xpsuc1th",
                ClientSecret = "yq9jUxl70QoOmwHxJ37h1rDoyJ5iz92Q",
                Resource = new List<string>() { "https://default.logto.app/api" },
                Scope = "all"
            });

            if (tokenResponse.IsError)
            {
                Console.WriteLine(tokenResponse.Error);
                Console.WriteLine(tokenResponse.ErrorDescription);
            }
            else
            {
                Console.WriteLine(tokenResponse.AccessToken);
                Console.WriteLine("\n\n");

                // call api
                var apiClient = new HttpClient();
                apiClient.SetBearerToken(tokenResponse.AccessToken);

                var response = await apiClient.GetAsync("https://logto.test.extimaging.com/api/applications");
                if (!response.IsSuccessStatusCode)
                {
                    Console.WriteLine(response.StatusCode);
                }
                else
                {
                    var doc = JsonDocument.Parse(await response.Content.ReadAsStringAsync()).RootElement;
                    Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(doc, new JsonSerializerOptions { WriteIndented = true }));
                }
            }


            #endregion

            return ResponseOutput.Ok();


        }

        public async Task<IResponseOutput> TestClientCredentialsOriginAsync()
        {
            #region 客户端方式获取logto 里面的信息
            {

                var baseUrl = "https://logto.test.extimaging.com";
                var appId = "v2mr2ndxwkxz0xpsuc1th";
                var appSecret = "yq9jUxl70QoOmwHxJ37h1rDoyJ5iz92Q";
                var apiAddress = "https://default.logto.app/api"; //这里是个坑
                var scope = "all";

                var opts = new RestClientOptions(baseUrl);
                using var client = new RestClient(opts);

                //https://bump.sh/logto/doc/logto-management-api/authentication
                var request = new RestRequest("oidc/token", Method.Post);
                request
                    .AddHeader("Content-Type", "application/x-www-form-urlencoded")
                    .AddParameter("grant_type", "client_credentials")
                    .AddParameter("client_id", appId)
                    .AddParameter("client_secret", appSecret)
                    .AddParameter("resource", apiAddress) //注意这里默认值地址和api 地址有区别
                    .AddParameter("scope", scope);


                var response = await client.ExecuteAsync<LogtoTokenResponse>(request);

                if (response.StatusCode == HttpStatusCode.OK)
                {
                    var tokenResponse = response.Data;

                    Console.WriteLine(tokenResponse.ToJsonStr());

                    #region 获取应用信息

                    var applicationRequest = new RestRequest($"/api/applications", Method.Get)
                        .AddHeader("Authorization", $"Bearer {tokenResponse.AccessToken}");

                    var applicationResponse = await client.ExecuteAsync(applicationRequest);
                    #endregion

                    #region 获取用户信息
                    //curl \
                    // -X GET https://[tenant_id].logto.app/api/users/{userId} \
                    // -H "Authorization: Bearer $ACCESS_TOKEN"

                    var userId = "4fqx4cb3438k";
                    var userInfoRequest = new RestRequest($"api/users/{userId}", Method.Get)
                        .AddHeader("Authorization", $"Bearer {tokenResponse.AccessToken}");


                    var userResponse = await client.ExecuteAsync<LogtoUser>(userInfoRequest);

                    Console.WriteLine(userResponse.Content);

                    #endregion
                }


            }
            #endregion

            return ResponseOutput.Ok();
        }
        #endregion

    }

    public static class PkceUtil
    {
        // 生成 code_verifier
        public static string GenerateCodeVerifier()
        {
            var bytes = new byte[64];
            using (var random = RandomNumberGenerator.Create())
            {
                random.GetBytes(bytes);
                return Convert.ToBase64String(bytes)
                    .TrimEnd('=')
                    .Replace('+', '-')
                    .Replace('/', '_');
            }
        }

        // 生成 code_challenge
        public static string GenerateCodeChallenge(string codeVerifier)
        {
            using (var sha256 = SHA256.Create())
            {
                var bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(codeVerifier));
                return Convert.ToBase64String(bytes)
                    .TrimEnd('=')
                    .Replace('+', '-')
                    .Replace('/', '_');
            }
        }
    }
}
