using DingTalk.Api;
using DingTalk.Api.Request;
using DingTalk.Api.Response;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XYY.Data.Standard;
using XYY.Service.Standard.DingDing.Dto;
using static DingTalk.Api.Response.OapiV2UserGetResponse;

namespace XYY.Service.Standard.DingDing
{
    public interface IDingDingService
    {
        Task<long> GetDingDingUserDepIdAsUserId(string userId);
        Task<string> GetDingDingUserIdAsPhone(string phone);
        Task<DingDingUserInfo> GetDingDingUserInfo(int xyyUserId);
        Task<string> GetTokenAsCache();
        Task<string> SendMessage(string userId, dynamic root);
        /// <summary>
        /// 根据钉钉Id获取用户信息
        /// </summary>
        /// <param name="uid"></param>
        /// <returns></returns>
        Task<UserGetResponseDomain> GetUserInfo(string uid);
    }

    public class DingDingService : IDingDingService
    {
        private const string UserCacheKey = "UserKey";
        private const string DingDingTokenCacheKey = "DingDingToken";
        IDistributedCache _cache;
        IUserInfoRepository _userInfoRepository;


        public DingDingService(IDistributedCache cache, IUserInfoRepository userInfoRepository)
        {
            _cache = cache;
            _userInfoRepository = userInfoRepository;
        }

        public async Task<long> GetDingDingUserDepIdAsUserId(string userId)
        {
            string token = await GetTokenAsCache();
            IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
            OapiV2UserGetRequest req = new OapiV2UserGetRequest();
            req.Userid = userId;
            OapiV2UserGetResponse rsp = client.Execute(req, token);
            return rsp.Result.DeptIdList[0];
        }

        public async Task<string> GetDingDingUserIdAsPhone(string phone)
        {
            string token = await GetTokenAsCache();
            IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getbymobile");
            OapiV2UserGetbymobileRequest req = new OapiV2UserGetbymobileRequest();
            req.Mobile = phone;
            OapiV2UserGetbymobileResponse rsp = client.Execute(req, token);
            if (rsp.IsError || !string.IsNullOrWhiteSpace(rsp.ErrMsg) || (!string.IsNullOrWhiteSpace(rsp.Errmsg)&&rsp.Errmsg!="ok"))
            {
                string msg = rsp.Errmsg;
                if(string.IsNullOrWhiteSpace(msg))
                {
                    msg = rsp.ErrMsg;
                }
                throw new Exception("获取钉钉用户信息失败：" + msg + $"({phone})");
            }
               
            return rsp.Result.Userid;
        }

        /// <summary>
        /// 获取钉钉，缓存过期时间为两小时
        /// </summary>
        /// <returns></returns>
        public async Task<string> GetTokenAsCache()
        {
            string token = await _cache.GetStringAsync(DingDingTokenCacheKey);
            if (string.IsNullOrEmpty(token))
            {
                token = GetToken();

                await _cache.SetAsync(DingDingTokenCacheKey, Encoding.UTF8.GetBytes(token), new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(2)
                });
            }
            return token;
            //return await Task.Run(() => { return "385ca6aea2a931f28f35ff34b1431469"; });
        }

        private static string GetToken()
        {
            IDingTalkClient tokenClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
            OapiGettokenRequest oapiGettokenRequest = new OapiGettokenRequest();
            oapiGettokenRequest.Appkey = "dingxucfxjsjiuzhlcg8";
            oapiGettokenRequest.SetHttpMethod("get");
            oapiGettokenRequest.Appsecret = "g5D4S6OEsGklJSED3-F7i4_BaAr3Wy0Z-rC41FV1d-8doF-9JwCgh5DaR4Mz68qf";
            OapiGettokenResponse rsp = tokenClient.Execute(oapiGettokenRequest);
            TokenResult tokenResult = Newtonsoft.Json.JsonConvert.DeserializeObject<TokenResult>(rsp.Body);
            string token;
            if (tokenResult.errmsg != "ok")
                throw new Exception("获取授权失败");
            else
                token = tokenResult.access_token;
            return token;
        }

        /// <summary>
        /// 根据钉钉Id获取用户信息
        /// </summary>
        /// <param name="uid"></param>
        /// <returns></returns>
        public async Task<UserGetResponseDomain> GetUserInfo(string uid)
        {
            string token = await GetTokenAsCache();
            IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");
            OapiV2UserGetRequest req = new OapiV2UserGetRequest();
            req.Userid = uid;
            OapiV2UserGetResponse rsp = client.Execute(req, token);

            return rsp.Result;
        }

        public async Task<string> SendMessage(string userId, dynamic root)
        {
            string token = await GetTokenAsCache();
            IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
            OapiMessageCorpconversationAsyncsendV2Request messageCorpconversationAsyncsendV2Request = new OapiMessageCorpconversationAsyncsendV2Request();
            messageCorpconversationAsyncsendV2Request.AgentId = 1362321125L;
            messageCorpconversationAsyncsendV2Request.UseridList = userId;

            messageCorpconversationAsyncsendV2Request.Msg = Newtonsoft.Json.JsonConvert.SerializeObject(root);
            var response = client.Execute(messageCorpconversationAsyncsendV2Request, token);
            return response.Errmsg;
        }

        /// <summary>
        /// 通过缓存查找钉钉用户信息
        /// </summary>
        /// <param name="xyyUserId">系统用户Id</param>
        /// <returns></returns>
        public async Task<DingDingUserInfo> GetDingDingUserInfo(int xyyUserId)
        {
            var key = UserCacheKey + "#" + xyyUserId;
            var userStr = await _cache.GetStringAsync(key);
            if (string.IsNullOrEmpty(userStr))
            {
                var info = await _userInfoRepository.GetAsync(xyyUserId);
                if (info == null)
                    throw new Exception("找不到当前用户的行运易帐户信息");
                if (string.IsNullOrEmpty(info.Phone))
                    throw new Exception("当前用户未设置电话信息");

                //钉钉获取用户Id
                if (string.IsNullOrWhiteSpace(info.Phone))
                    return null;

                string ddUserId = await GetDingDingUserIdAsPhone(info.Phone);
                long ddDepId = await GetDingDingUserDepIdAsUserId(ddUserId);
                var user = new DingDingUserInfo
                {
                    UserId = ddUserId,
                    DepId = ddDepId
                };
                userStr = Newtonsoft.Json.JsonConvert.SerializeObject(user);
                await _cache.SetStringAsync(key, userStr);
            }

            return Newtonsoft.Json.JsonConvert.DeserializeObject<DingDingUserInfo>(userStr);
        }
    }
}
