using Hotline.Application.Identity;
using Hotline.Caching.Interfaces;
using Hotline.Share.Dtos.Identity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Cryptography;
using System.Text;
using Hotline.Api.Filter;
using Hotline.Application.Systems;
using Hotline.Configurations;
using Hotline.Settings;
using Microsoft.Extensions.Options;
using XC.RSAUtil;
using XF.Domain.Constants;
using XF.Domain.Exceptions;
using Hotline.Share.Dtos.Snapshot;
using Swashbuckle.AspNetCore.Annotations;
using NETCore.Encrypt;

namespace Hotline.Api.Controllers;

public class IdentityController : BaseController
{
    private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
    private readonly IIdentityAppService _identityAppService;
    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
    private readonly ISystemLogApplication _iSystemLogApplication;

    private const string PublicKey = @"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgw+/x6IQPkH0A4eoF63j
kLThsOXWyNBdcL9LATGy/G1yTHOr1RyKJB//iNug+V8DIoIHuFTlhgLHDbSqxvRW
MONxIIF289riS6bDI4Ox/pFmOfmElFRk0lKGihaTE2Aefd6g/N+RfLLaHWztY+/v
oVeDTiOIw9y3tokIxjKwuJ/mQ66MkKh78AqQjjSD/3jcBP8ZhMyCJOK9XQcqvhD6
WBFWkxlAqKOWggDU7YohfrbNkg3bd0oGE6zCE2EHhkcQbzGCh3lu1zf4TfKMXD+P
Prr5JWDNYQTXFQklqgae+Puge7xxZGYRoi5YpIUnkQGm6zpPxhIOdxlz+Yb5geSJ
UQIDAQAB
-----END PUBLIC KEY-----";
    private const string PrivateKey = @"-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAgw+/x6IQPkH0A4eoF63jkLThsOXWyNBdcL9LATGy/G1yTHOr
1RyKJB//iNug+V8DIoIHuFTlhgLHDbSqxvRWMONxIIF289riS6bDI4Ox/pFmOfmE
lFRk0lKGihaTE2Aefd6g/N+RfLLaHWztY+/voVeDTiOIw9y3tokIxjKwuJ/mQ66M
kKh78AqQjjSD/3jcBP8ZhMyCJOK9XQcqvhD6WBFWkxlAqKOWggDU7YohfrbNkg3b
d0oGE6zCE2EHhkcQbzGCh3lu1zf4TfKMXD+PPrr5JWDNYQTXFQklqgae+Puge7xx
ZGYRoi5YpIUnkQGm6zpPxhIOdxlz+Yb5geSJUQIDAQABAoIBAAe+312BKUbsp0BV
fOyCqoTLqTJHBcBneWY86pte9bjaZQYPU1PsdF452o8a38gXwpErBcwcjwCyWv48
iQKUv8qdiSWGe+Jh3hGM1lKGfsyl3i3wnlJqgcI2U1zc2a4BoREHnmm4yBnfs2lI
HegpRCG7u3cGPZfJtxJyxdHPfsc3wk8sXt+Byqkuym87l0a8wEF7b33f2hP2R7m/
37qYvTaGX3yN4s1rssQ3wBEfHEsesQmrQrEkRIUnWfgpkH3FdR5T1V4USC6GhM6x
sIxqwBBYLL2LhVcNEifegqHtLZOw0VfUfpvoKnH5omSjUP5X+c8dmY9KPoKGpYFT
l09fiRMCgYEAwSAmJr8G/xOCPtkRZ9qpxOwAeqA9iEhB3ViIydESrYMZGUaIKAWV
ofOuDIdaMgW/2hyQtJasAnlX87Za7iODcBAMMAPSNiLEXk9nHWO+Xw/oMakgS5Dg
uE2J02Bn4KFTCGALtfo70A40kkikkR2UdD4RG6j+DgI2JxxrCgaKiIMCgYEArbrv
cvJs62LlvOFdVCY3mWEJkoBbStHGq2GdtZ5Rx9oNqiy3j/xT7Wav061OPCaC2rcd
ALEH7AA3JJtAMr6QRv3HYyd2NIrlqS6pn4tInIpqlarrnVkkOk0WhsWVkScQJyx6
eLKQ24zEF3wHslrRpHcclCWjtQ52TmWOuUvy9psCgYAWw6BbntbHSFho6hNIJ5kt
Uhg4XB0ErGe/HIl7KH7IHxTdStgPx6C8p0mTxnyWOuFDZ2yTLNN3sy/v1UXgniUH
F40oN7sWkICPEVL5PuGYuPpIqEPbRGeIsfMWDF4SN1HfQdr/h1B3lMUTnSZwyIjQ
LuS7Wu8fXZlegNYJJ3462wKBgE5TSF9vktGw/djhVj15GXoKONGXExGxcDuWQA9A
+Kf81EpT7NJ6tbADquPpb6tIxZgsFGRabDLnifT0FcaLCesnwXwfr3hS4uYaxpjK
qAsDkLg3nhCLvvyWAsDyVdNiZDL1J6ZBA3Qoi8P2xFWSApB+ryDPs3YOtiH0QZui
9UBfAoGBAIQ2uv4J7ql++EpNNtLzOhTEpyjWS+qRSZRRXfKN2lm7e7czOsSpKIJx
Q9PP8NTEmKqdI3WVFYqW/OlOFC6sjiscTOOn9Tc5Mrcn8ocCjAPjkhkCCVRMiJnv
jxrWXHbT1FB6DqkdOnBbQqS1Azqz5HxLlSyEK3F60e3SgB5iZsDZ
-----END RSA PRIVATE KEY-----";

    private const string AesKey = "qlzeJrbj0CPkHdFBvEAxX47Y4nCbBPZW";
    private const string AesIv = "JxeDP0sgnPJdH9fE";

    public IdentityController(
        IOptionsSnapshot<AppConfiguration> appOptions,
        IIdentityAppService identityAppService,
        ISystemSettingCacheManager systemSettingCacheManager,
        ISystemLogApplication iSystemLogApplication)
    {
        _appOptions = appOptions;
        _identityAppService = identityAppService;
        _systemSettingCacheManager = systemSettingCacheManager;
        _iSystemLogApplication = iSystemLogApplication;
    }

    /// <summary>
    /// 登录
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [AllowAnonymous]
    [HttpPost("login")]
    [LogFilter("", false)]
    public async Task<string> Login([FromBody] LoginDto dto)
    {
        dto = Decrypt(dto);
        var res = await _identityAppService.LoginAsync(dto, HttpContext.RequestAborted);
        dto.Password = string.Empty;
        await _iSystemLogApplication.AddLog("账号登录", res, dto, HttpContext, dto.Username);
        return res;
    }

    /// <summary>
    /// 登录
    /// </summary>
    [AllowAnonymous]
    [HttpPost("login-sign")]
    public async Task<string> Login([FromBody] LoginSignatureDto dto)
    {
        var request = Decrypt(dto.Signature);
        if (request is null)
            throw UserFriendlyException.SameMessage("用户名或密码错误！");
        var res = await _identityAppService.LoginWithSignatureAsync(request, HttpContext.RequestAborted);
        request.Password = string.Empty;
        await _iSystemLogApplication.AddLog("账号登录", res, request, HttpContext, request.Username);
        return res;
    }

    /// <summary>
    /// 获取微信openId
    /// </summary>
    /// <param name="dto">微信小程序 Code</param>
    /// <returns>登录成功, 用户是新用户, 需要调用获取用户手机号码 third/phone 接口</returns>
    [AllowAnonymous]
    [HttpPost("third/token")]
    public async Task<Dictionary<string, object>> GetThirdTokenAsync([FromBody] ThirdTokenInDto dto)
        => await _identityAppService.GetThirdTokenAsync(dto, HttpContext.RequestAborted);

    /// <summary>
    /// 第三方登录
    /// </summary>
    /// <returns></returns>
    [AllowAnonymous]
    [LogFilterAlpha("老系统微信用户登录")]
    [HttpPost("third/login")]
    public async Task<Dictionary<string, object>> GetThirdLoginAsync([FromBody] ThirdOpenIdInDto dto)
            => await _identityAppService.GetThirdTokenAsync(dto, HttpContext.RequestAborted);

    /// <summary>
    /// 根据OpenId刷新令牌
    /// </summary>
    /// <param name="openId"></param>
    /// <returns></returns>
    [HttpGet("third/refresh")]
    [LogFilterAlpha("微信用户刷新Token")]
    [AllowAnonymous]
    public async Task<Dictionary<string, object>> RefreshTokenAsync(string openId)
        => await _identityAppService.RefreshTokenAsync(openId, HttpContext.RequestAborted);

    [AllowAnonymous]
    [ApiExplorerSettings(IgnoreApi = true)]
    [HttpPost("token")]
    public async Task<string> LoginWithoutCrypt([FromBody] LoginDto dto)
    {
        return await _identityAppService.LoginAsync(dto, HttpContext.RequestAborted);
    }

    /// <summary>
    /// 登录页系统配置
    /// </summary>
    /// <returns></returns>
    [AllowAnonymous]
    [HttpGet("login-page-info")]
    public async Task<LoginPageInfoDto> LoginPageInfo()
    {
        var SysName = _systemSettingCacheManager.GetSetting(SettingConstants.SysName).SettingValue?.FirstOrDefault();
        var loginImage = _systemSettingCacheManager.GetSetting(SettingConstants.LoginImage).SettingValue?.FirstOrDefault();
        var changePwdImage = _systemSettingCacheManager.GetSetting(SettingConstants.ChangePwdImage).SettingValue?.FirstOrDefault();
        var faviconImage = _systemSettingCacheManager.GetSetting(SettingConstants.FaviconImage).SettingValue?.FirstOrDefault();
        var menuLogoImage = _systemSettingCacheManager.GetSetting(SettingConstants.MenuLogoImage).SettingValue?.FirstOrDefault();
        var menuLogoImageMini = _systemSettingCacheManager.GetSetting(SettingConstants.MenuLogoImageMini).SettingValue?.FirstOrDefault();
        var IsLoginMessageCode = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsLoginMessageCode).SettingValue[0]);
        var recordNumber = _systemSettingCacheManager.GetSetting(SettingConstants.RecordNumber).SettingValue?.FirstOrDefault();
        var cityAbbr = _systemSettingCacheManager.GetSetting(SettingConstants.CityAbbr).SettingValue?.FirstOrDefault();
        var operate = _systemSettingCacheManager.GetSetting(SettingConstants.Operate).SettingValue?.FirstOrDefault();
        var techSupport = _systemSettingCacheManager.GetSetting(SettingConstants.TechSupport).SettingValue?.FirstOrDefault();
        var cityCode = _systemSettingCacheManager.GetSetting(SettingConstants.CityCode).SettingValue?.FirstOrDefault();
        var cityName = _systemSettingCacheManager.GetSetting(SettingConstants.CityName).SettingValue?.FirstOrDefault();

        return new LoginPageInfoDto
        {
            CityAbbr = cityAbbr,
            CityName = cityName,
            CityCode = cityCode,
            TechSupport = techSupport,
            Operate = operate,
            RecordNumber = recordNumber,
            SysName = SysName,
            LoginImage = loginImage,
            ChangPwdImage = changePwdImage,
            FaviconImage = faviconImage,
            MenuLogoImage = menuLogoImage,
            MenuLogoImageMini = menuLogoImageMini,
            IsLoginMessageCode = IsLoginMessageCode,
            AppScope = _appOptions.Value.AppScope,
            CallCenterSocketUrl = _systemSettingCacheManager.GetSetting(SettingConstants.CallCenterSocketUrl).SettingValue?.FirstOrDefault(),
        };
    }

    private LoginDto Decrypt(LoginDto dto)
    {
        if (string.IsNullOrEmpty(dto.Username) || string.IsNullOrEmpty(dto.Password))
            throw UserFriendlyException.SameMessage("非法参数");

        var pkcs1 = new RsaPkcs1Util(Encoding.UTF8, PublicKey, PrivateKey);
        try
        {
            var uname = pkcs1.Decrypt(dto.Username, RSAEncryptionPadding.Pkcs1);
            var pwd = pkcs1.Decrypt(dto.Password, RSAEncryptionPadding.Pkcs1);
            var msgCode = pkcs1.Decrypt(dto.MsgCode, RSAEncryptionPadding.Pkcs1);
            return new LoginDto { Username = uname, Password = pwd, MsgCode = msgCode };
        }
        catch (Exception e)
        {
            throw new UserFriendlyException($"解密失败：{e.Message}", "无效参数");
        }
    }

    private LoginWithSignatureRequest? Decrypt(string signature)
    {
        if (string.IsNullOrEmpty(signature)) return null;
        var decrypted = EncryptProvider.AESDecrypt(signature, AesKey, AesIv);
        if(string.IsNullOrEmpty(decrypted)) return null;
        return System.Text.Json.JsonSerializer.Deserialize<LoginWithSignatureRequest>(decrypted,
            JsonDefaults.DefaultJsonSerializerOptionsWithCamelCase);
    }
}