using System.Security.Authentication;
using System.Text;
using System.Xml.Serialization;
using Microsoft.Extensions.Logging;
using NewRock.Sdk.Extensions;
using NewRock.Sdk.Security;

namespace NewRock.Sdk
{
    public class NewRockClient : INewRockClient
    {
        private readonly IHttpClientFactory _httpClientFactory;
        private readonly IAuthorizeGenerator _authorizeGenerator;
        private readonly ILogger<NewRockClient> _logger;

        public NewRockClient(
            IHttpClientFactory httpClientFactory,
            IAuthorizeGenerator authorizeGenerator,
            ILogger<NewRockClient> logger)
        {
            _httpClientFactory = httpClientFactory;
            _authorizeGenerator = authorizeGenerator;
            _logger = logger;
        }

        public async Task<TResponse?> ExecuteAsync<TRequest, TResponse>(TRequest request, string key, int expired, CancellationToken cancellationToken)
            where TRequest : INewRockRequest
            where TResponse : NewRockResponse
        {
            var client = _httpClientFactory.CreateClient(Defaults.DeviceName);
            client.DefaultRequestHeaders.ConnectionClose = true;
            var authorize = _authorizeGenerator.GetAuthorize(key, expired);
            var requestContent = request.Serialize(authorize);
            _logger.LogInformation($"request: {requestContent}");
            var content = new StringContent(requestContent, Encoding.UTF8, "application/xml");

            //try...catch为了解决OM设备方主动断开TCP连接
            try
            {
                using var responseMessage = await client.PostAsync(string.Empty, content, cancellationToken);
                using var respContent = responseMessage.Content;
                var respContentString = await respContent.ReadAsStringAsync(cancellationToken);
                _logger.LogInformation($"response: {respContentString}");
                if (respContentString.Contains("<Event"))
                    return default;

                var authResult = respContentString.Authentication();
                if (authResult != null)
                {
                    throw new AuthenticationException(
                        string.Format("请求认证失败, code: {code}, err: {err}", authResult.Code, authResult.Reason));
                }

                return respContentString.DeserializeWithErrorMsg<TResponse>();
                //var respContentStream = await respContent.ReadAsStreamAsync(cancellationToken);
                //return respContentStream.Deserialize<TResponse>();
            }
            catch (Exception e)
            {
                if (!string.IsNullOrEmpty(e.Message))
                    _logger.LogError(e.Message);
                return null;
            }
        }
    }


    public class NewRockResponse
    {
        public bool Success => Error is null;

        [XmlIgnore]
        public NewRockErrorResponse? Error { get; set; }
    }

    [XmlRoot("Event")]
    public class NewRockErrorResponse
    {
        [XmlAttribute("attribute")]
        public string Attribute { get; set; }

        [XmlElement("err")]
        public NewRockError Error { get; set; }
    }

    public class NewRockError
    {
        [XmlAttribute("code")]
        public string Code { get; set; }

        [XmlAttribute("reason")]
        public string Reason { get; set; }
    }

    [XmlRoot("err")]
    public class UnauthorizedResponse : NewRockResponse
    {
        [XmlAttribute("code")]
        public string Code { get; set; }

        [XmlAttribute("reason")]
        public string Reason { get; set; }
    }
}
