using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Net.Http.Json;
using System.Net;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
using System.Security.Authentication.ExtendedProtection;
using Newtonsoft.Json.Linq;
using System.Text.Json.Serialization.Metadata;

namespace HttpClientStudy.UnitTest
{
    /// <summary>
    /// 基础HttpClient 测试
    /// </summary>
    public class NormalHttpClientTest
    {
        private readonly ITestOutputHelper _logger;

        public NormalHttpClientTest(ITestOutputHelper outputHelper) 
        {
            _logger = outputHelper;
        }

        #region GET请求

        [Fact]
        public async Task GetAllAccounts_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var responseMessage = await  httpClient.GetAsync("/api/Normal/GetAllAccounts");

            responseMessage.EnsureSuccessStatusCode();

            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<List<Account>>>();
            Assert.IsType<BaseResult<List<Account>>>(result);
            Assert.Equal(1, result.Code);
            Assert.NotNull(result.Data);
        }

        /// <summary>
        /// GET 请求
        /// (默认参数方式:url传参)
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task GetAccount_Id_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var responseMessage = await httpClient.GetAsync("/api/Normal/GetAccount?Id=2");

            responseMessage.EnsureSuccessStatusCode();

            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
            Assert.IsType<BaseResult<Account>>(result);
            Assert.Equal(1, result.Code);
            Assert.Equal(2, result.Data?.Id);
        }

        /// <summary>
        /// GET 请求
        /// (路由传参)
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task GetAccount_Route_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var responseMessage = await httpClient.GetAsync("/api/Normal/GetAccount/管理员02");

            responseMessage.EnsureSuccessStatusCode();

            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
            Assert.IsType<BaseResult<Account>>(result);
            Assert.Equal(1, result.Code);
            Assert.Equal("管理员02", result.Data?.Name);
        }

        /// <summary>
        ///  GET 请求
        /// (中文参数:现在浏览器直接支持,为最大兼容老旧浏览器使用url编码)
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task GetAccountByName_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var ChineseName = System.Net.WebUtility.UrlEncode("管理员01");
            var ChineseName2 = System.Net.WebUtility.UrlEncode("管理员02");

            //现在浏览器直接支持中文参数
            //var responseMessage = await httpClient.GetAsync("/api/Normal/GetAccountByName?ChineseName=管理员01&ChineseName2=管理员02");

            //兼容老浏览器写法
            var responseMessage = await httpClient.GetAsync($"/api/Normal/GetAccountByName?ChineseName={ChineseName}&ChineseName2={ChineseName2}");

            responseMessage.EnsureSuccessStatusCode();

            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<List<Account>>>();
            Assert.IsType<BaseResult<List<Account>>>(result);
            Assert.Equal(1, result.Code);
            Assert.Equal(2, result.Data?.Count);
        }

        /// <summary>
        /// GET 请求
        /// (查询参数传参)
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task GetAccountByRole_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var responseMessage = await httpClient.GetAsync("/api/Normal/GetAccountByRole?role=Admin");

            responseMessage.EnsureSuccessStatusCode();

            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<List<Account>>>();
            Assert.IsType<BaseResult<List<Account>>>(result);
            Assert.Equal(1, result.Code);
            //每项的角色都是查询的角色
            Assert.False(result.Data?.Any(d=>d.Role != "Admin"));
        }

        /// <summary>
        /// GET 请求
        /// (请求头传参:中文必须Url编码,服务端Url解码后使用)
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task GetAccountFromHeader_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            //中文参数必须先编码
            httpClient.DefaultRequestHeaders.Add("name", System.Net.WebUtility.UrlEncode("管理员01"));
            var responseMessage = await httpClient.GetAsync("/api/Normal/GetAccountFromHeader");

            responseMessage.EnsureSuccessStatusCode();

            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
            Assert.IsType<BaseResult<Account>>(result);
            Assert.Equal(1, result.Code);
            Assert.Equal(1,result.Data?.Id);
        }

        /// <summary>
        /// GET 请求
        /// (客户端不传参,服务端参数直接来由IoC中注入的服务)
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task GetAccountByService_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var responseMessage = await httpClient.GetAsync("/api/Normal/GetAccountFromServices");

            responseMessage.EnsureSuccessStatusCode();

            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
            Assert.IsType<BaseResult<Account>>(result);
            Assert.Equal(1, result.Code);
            Assert.Equal("服务注入示例",result.Data?.Name);
        }

        /// <summary>
        /// GET 请求
        /// (直接调用System.Net.Http.Json类的扩展方法GetFromJsonAsync 获取 Json 结果)
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task Get_From_Json_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var result = await httpClient.GetFromJsonAsync<BaseResult<Account>>("/api/Normal/GetAccountFromServices");

            Assert.IsType<BaseResult<Account>>(result);
            Assert.Equal(1, result.Code);
            Assert.Equal("服务注入示例", result.Data?.Name);
        }
        #endregion

        #region PUT 请求
        /// <summary>
        /// Put 请求
        /// (新建或替换、更新资源)
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task PutDemo_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var responseMessage = await httpClient.PutAsync("/api/Normal/PutDemo?id=2",null);

            responseMessage.EnsureSuccessStatusCode();

            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var result = await responseMessage.Content.ReadAsStringAsync();

        }
        #endregion

        #region HEAD 请求
        /// <summary>
        /// Head 请求
        /// 注意:HttpClient没有直接提供HEAD请求方法:
        ///       步骤1:构建 HttpRequestMessage 对象,设置HttpMethod.Head
        ///       步骤2:把上步构建的HttpRequestMessage 对象,作为参数传递给 HttpClient实例的 Send 或 SendAsync 方法
        /// </summary>
        /// <returns></returns>
        [Fact]
        public async Task HeadDemo_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var requestMessage = new HttpRequestMessage(HttpMethod.Head, "/api/Normal/HeadDemo?Id=2");

            HttpResponseMessage responseMessage = await httpClient.SendAsync(requestMessage);

            responseMessage.EnsureSuccessStatusCode();

            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            //head请求没有返回体
            var result = await responseMessage.Content.ReadAsStringAsync();
            Assert.Empty(result);
        }
        #endregion

        #region POST 请求

        [Fact]
        public async Task PostSimple_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            //响应
            var responseMessage = await httpClient.PostAsync("/api/Normal/PostSimple", null);

            //响应正常
            Assert.True(responseMessage.IsSuccessStatusCode);
            Assert.NotNull(responseMessage);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<string>>();
            Assert.IsType<BaseResult<string>>(result);  
            Assert.Equal(1, result?.Code);
        }

        [Fact]
        public async Task PostCreate_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            //参数
            var para = new Account() {Id=100, Name="小明", Password="123456", Role="Admin" };

            //请求体
            var plainContent = new StringContent(JsonConvert.SerializeObject(para), Encoding.UTF8, System.Net.Mime.MediaTypeNames.Application.Json);

            //发POST请求
            var responseMessage = await httpClient.PostAsync("/api/Normal/PostCreate", plainContent);

            //确保响应正常
            responseMessage.EnsureSuccessStatusCode();


            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var text = await responseMessage.Content.ReadAsStringAsync();

            var result = JsonConvert.DeserializeObject<CreatedAtActionResult> (text);

            Assert.IsType<CreatedAtActionResult>(result);
            Assert.Equal(201, result.StatusCode);
            Assert.IsType<Newtonsoft.Json.Linq.JObject>(result.Value);

            //新创建的对象
            var account = JsonConvert.DeserializeObject<Account>(value: result.Value.ToString() ?? "");

            Assert.NotNull(account);
            Assert.Equal(100,account.Id);

            //由于构造函数等原因,直接使用ReadFromJsonAsync,会异常。
            //CreatedAtActionResult? result = await responseMessage.Content.ReadFromJsonAsync<CreatedAtActionResult>(new JsonSerializerOptions() { IncludeFields=true, PropertyNameCaseInsensitive=true});
        }

        [Fact]
        public async Task PostUpdate_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            //参数
            var para = new Account() { Id = 1, Name = "小明", Password = "123456", Role = "Admin" };

            //发POST请求
            var responseMessage = await httpClient.PostAsJsonAsync("/api/Normal/PostUpdate", para);

            //确保响应正常
            responseMessage.EnsureSuccessStatusCode();


            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
            Assert.IsType<BaseResult<Account>>(result);
            Assert.Equal(1, result.Code);

            Assert.Equal(1, result.Data?.Id);
        }

        [Fact]
        public async Task PostRemove_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var para_id = 2;

            //发POST请求(URL传参)
            var responseMessage = await httpClient.PostAsync($"/api/Normal/PostRemove?Id={para_id}", null);

            //确保响应正常
            responseMessage.EnsureSuccessStatusCode();


            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
            Assert.IsType<BaseResult<Account>>(result);
            Assert.Equal(1, result.Code);

            Assert.Equal(para_id, result.Data?.Id);
        }
        #endregion

        #region DELETE 请求

        [Fact]
        public async Task Delete_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var para_id = 2;

            //发POST请求(URL传参)
            var responseMessage = await httpClient.DeleteAsync($"/api/Normal/Delete?Id={para_id}");

            //确保响应正常
            responseMessage.EnsureSuccessStatusCode();


            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<int>>();
            Assert.IsType<BaseResult<int>>(result);
            Assert.Equal(1, result.Code);

            Assert.Equal(para_id, result.Data);
        }

        [Fact]
        public async Task Delete2_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var account = new Account() { Id = 2, Name = "小明", Password = "123456", Role = "Admin" };

            var requestMessage = new HttpRequestMessage(HttpMethod.Delete, "/api/Normal/DeleteForJsonData");
            //Delete 默认不使用请求体,如果使用的话,需要Content配合 RequestMessage
            requestMessage.Content = JsonContent.Create(account);

            //也可以下面的,极少有使用(可自定义JsonSerializerOptions)
            //requestMessage.Content = JsonContent.Create(account,JsonTypeInfo.CreateJsonTypeInfo<Account>( JsonSerializerOptions.Default),new System.Net.Http.Headers.MediaTypeHeaderValue("application/json","utf-8"));

            //发Delete请求(带json请求体)
            var responseMessage = await httpClient.SendAsync(requestMessage);

            //确保响应正常
            responseMessage.EnsureSuccessStatusCode();

            Assert.NotNull(responseMessage);
            Assert.True(responseMessage.IsSuccessStatusCode);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<Account>>();
            Assert.IsType<BaseResult<Account>>(result);
            Assert.Equal(1, result.Code);
        }
        #endregion

        #region OPTIONS 请求
        [Fact]
        public async Task OPTIONS_Test()
        {
            HttpClient httpClient = new HttpClient()
            {
                BaseAddress = new Uri(TestConfig.WebApiBaseUrl),
            };

            var requestMessage = new HttpRequestMessage(HttpMethod.Options, "/api/Normal/OptionsSimple");

            //响应
            var responseMessage = await httpClient.SendAsync(requestMessage);

            //响应正常
            Assert.True(responseMessage.IsSuccessStatusCode);
            Assert.NotNull(responseMessage);

            var result = await responseMessage.Content.ReadFromJsonAsync<BaseResult<string>>();
            Assert.IsType<BaseResult<string>>(result);
            Assert.Equal(1, result?.Code);
        }
        #endregion

        #region PATCH 请求
        #endregion

        #region TRACE 请求
        #endregion

        #region CONNECT 请求
        #endregion
    }
}