using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Performance.DtoModels;
using Performance.DtoModels.AppSettings;
using Performance.DtoModels.OAuth;
using Performance.Infrastructure;
using Performance.Infrastructure.Helper;
using Performance.Repository;

namespace Performance.Services
{
    public class OAuthService : IAutoInjection
    {
        private readonly UserService _userService;
        private readonly ILogger<OAuthService> _logger;
        private readonly IConfiguration _configuration;
        private readonly IHttpClientFactory _factory;
        private readonly PerforUserRepository _userRepository;
        private readonly PerforHospitalRepository _hospitalRepository;

        public OAuthService(UserService userService,
                            ILogger<OAuthService> logger,
                            IConfiguration configuration,
                            IHttpClientFactory factory,
                            PerforUserRepository userRepository,
                            PerforHospitalRepository hospitalRepository)
        {
            _userService = userService;
            _logger = logger;
            _configuration = configuration;
            _factory = factory;
            _userRepository = userRepository;
            _hospitalRepository = hospitalRepository;
        }

        public async Task<string> Authorize()
        {
            _logger.LogInformation("OAuth授权启动");
            try
            {
                var client = _factory.CreateClient();
                client.Timeout = TimeSpan.FromSeconds(20);

                Dictionary<string, string> pairs = new Dictionary<string, string>()
                {
                    { "client_id", _configuration.GetValue<string>("oauth2:client_id", "") },
                    { "response_type", _configuration.GetValue<string>("oauth2:response_type", "code") },
                    { "redirect_uri", _configuration.GetValue<string>("oauth2:redirect_uri", "") },
                    { "scope", _configuration.GetValue<string>("oauth2:scope", "") },
                    { "state", _configuration.GetValue<string>("oauth2:state", Guid.NewGuid().ToString("N")) },
                };

                var queryParams = pairs.Where(w => !string.IsNullOrEmpty(w.Value)).Select(w => $"{w.Key}={w.Value}");

                var authorize_url = _configuration.GetValue<string>("oauth2:authorize_url");
                var url = $"{authorize_url}?{string.Join('&', queryParams)}";

                _logger.LogInformation($"OAuth授权启动：authorize_url={url}");

                return url;
            }
            catch (Exception ex)
            {
                _logger.LogError($"OAuth授权启动：请求异常：{ex}");
            }
            return "";
        }

        public async Task<OAuthResponse<IOAuthResponse>> Token(string code, string state)
        {
            _logger.LogInformation($"OAuth授权接受回调请求：code={code}&state={state}");

            try
            {
                var client = _factory.CreateClient();

                Dictionary<string, string> pairs = new Dictionary<string, string>()
                {
                    { "grant_type", _configuration.GetValue<string>("oauth2:grant_type", "authorization_code") },
                    { "code", code },
                    { "client_id", _configuration.GetValue<string>("oauth2:client_id", "") },
                    { "client_secret", _configuration.GetValue<string>("oauth2:client_secret", "") },
                    { "redirect_uri", _configuration.GetValue<string>("oauth2:redirect_uri", "") },
                };
                var queryParams = pairs.Where(w => !string.IsNullOrEmpty(w.Value)).Select(w => $"{w.Key}={w.Value}");

                var token_url = _configuration.GetValue<string>("oauth2:token_url");
                var url = $"{token_url}?{string.Join('&', queryParams)}";
                // 测试模式直接返回URL用于调试
                if (_configuration.GetValue("oauth2:test_mode", false))
                {
                    throw new PerformanceException($"OAuth授权接受回调请求测试模式：{url}");
                }

                var response = await client.GetAsync(url);
                var resContent = await response.Content.ReadAsStringAsync();
                _logger.LogInformation($"OAuth授权接受回调请求：响应状态:{(int)response.StatusCode};{resContent}");
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    var data = await response.Content.ReadFromJsonAsync<OAuthErrorResponse>();
                    _logger.LogInformation($"OAuth授权接受回调请求：请求结果={data}");
                    return new OAuthResponse<IOAuthResponse>((int)response.StatusCode, data);
                }
                else
                {
                    var data = await response.Content.ReadFromJsonAsync<TokenResponse>();
                    _logger.LogInformation($"OAuth授权接受回调请求：请求结果={JsonHelper.Serialize(data)}");
                    return new OAuthResponse<IOAuthResponse>((int)response.StatusCode, data);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"OAuth授权接受回调请求：请求异常：{ex}");
            }
            return new OAuthResponse<IOAuthResponse>((int)HttpStatusCode.InternalServerError, null);
        }

        public async Task<OAuthResponse<IOAuthResponse>> GetUserInfo(string access_token)
        {
            _logger.LogInformation($"OAuth授权获取用户属性信息：access_token={access_token}");
            try
            {
                var client = _factory.CreateClient();

                var get_user_info_url = _configuration.GetValue<string>("oauth2:get_user_info_url");
                var url = $"{get_user_info_url}?access_token={access_token}";
                var response = await client.GetAsync(url);
                var resContent = await response.Content.ReadAsStringAsync();
                _logger.LogInformation($"OAuth授权获取用户属性信息：响应状态:{(int)response.StatusCode};{resContent}");
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    var data = await response.Content.ReadFromJsonAsync<OAuthErrorResponse>();
                    _logger.LogInformation($"OAuth授权获取用户属性信息：请求结果={data}");
                    return new OAuthResponse<IOAuthResponse>((int)response.StatusCode, data);
                }
                else
                {
                    var data = await response.Content.ReadFromJsonAsync<OAuthUserInfoResponse>();
                    _logger.LogInformation($"OAuth授权获取用户属性信息：请求结果={JsonHelper.Serialize(data)}");
                    return new OAuthResponse<IOAuthResponse>((int)response.StatusCode, data);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError($"OAuth授权获取用户属性信息：请求异常：{ex}");
            }
            return new OAuthResponse<IOAuthResponse>((int)HttpStatusCode.InternalServerError, null);
        }

        public UserIdentity GetOrInitUserInfo(OAuthUserInfoResponse userData)
        {
            var userId = 0;
            var user = _userRepository.GetEntity(w => w.Login == userData.desc);
            if (user != null)
            {
                userId = user.ID;
            }
            else
            {
                var roleid = _configuration.GetValue("oauth2:default_roleid", $"{(int)Role.绩效查询}");
                var roleIds = Array.ConvertAll(roleid.Split(",", StringSplitOptions.RemoveEmptyEntries), item => int.Parse(item));

                var mail = _configuration.GetValue("oauth2:default_mail", "{0}@oauth.com");
                var password = _configuration.GetValue("oauth2:default_password", "123456");
                var hosid = _configuration.GetValue("oauth2:default_hosid", 0);
                if (hosid <= 0)
                    hosid = _hospitalRepository.GetEntity(w => !w.HosName.Contains("测试"))?.ID ?? 0;

                var userRequest = new UserRequest
                {
                    Login = userData.desc,
                    RealName = userData.name,
                    Password = PwdHelper.MD5(password),
                    HosIDArray = new int[] { hosid },
                    RoleArr = roleIds,
                    States = (int)States.Enabled,
                    Remark = JsonHelper.Serialize(userData),
                    Department = "",
                    Mail = string.Format(mail, userData.desc),
                };

                userId = _userService.InsertUser(userRequest, -1001).UserID;
            }
            return _userService.GetUserIdentity(userId);
        }
    }
}
