using Tea;
using Tea.Utils;
using System.IO;
using AlibabaCloud.OpenApiClient;
using AlibabaCloud.OpenApiClient.Models;
using AlibabaCloud.SDK.Dingtalkdrive_1_0;
using AlibabaCloud.SDK.Dingtalkdrive_1_0.Models;
using DingTalk.Api;
using DingTalk.Api.Request;
using DingTalk.Api.Response;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Text;
using System.Threading.Tasks;
using XYY.Data.Standard;
using XYY.Model.Standard;
using System.Linq;
using System.Collections.Generic;
using Client = AlibabaCloud.SDK.Dingtalkdrive_1_0.Client;
using Aliyun.OSS.Common.Authentication;
using Aliyun.OSS.Common;
using Aliyun.OSS;
using Org.BouncyCastle.Crypto.Tls;

namespace XYY.Service.Standard.Finance
{
    public interface IDingDingBaseService
    {
        Task<OapiV2UserGetResponse.UserGetResponseDomain> GetDingDingUserAsUserId(string userId);
        Task<string> GetDingDingUserIdAsPhone(string phone);
        Task<DingDingUserInfo> GetDingDingUserInfo(int userId);
        Task<string> GetTokenAsCache();
        Task<string> SendMessage(string userId, dynamic root);
        Task<string> UpdateFile(string filePath, string fileName);
        /// <summary>
        /// 根据钉钉Id获取用户信息
        /// </summary>
        /// <param name="uid"></param>
        /// <returns></returns>
        Task<User_Info> GetUserInfo(string uid);

        Task<CspaceFile> UpdateFileToCspace(DingDingUserInfo user, string fileName, string filePath);
        Task<string> RefuseDingTalk(string code, string msg, long taskId);
    }
    public class DingDingBaseService : IDingDingBaseService
    {

        private const string UserCacheKey = "UserKey";
        private const string DingDingTokenCacheKey = "DingDingToken";
        IDistributedCache _cache;
        IUserInfoRepository _userInfoRepository;

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

        private static string GetToken()
        {
            //获取token

            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;
        }

        public async Task<OapiV2UserGetResponse.UserGetResponseDomain> GetDingDingUserAsUserId(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;
        }

        /// <summary>
        /// 根据钉钉Id获取用户信息
        /// </summary>
        /// <param name="uid"></param>
        /// <returns></returns>
        public async Task<User_Info> 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);
            if (rsp.IsError)
                throw new Exception(rsp.Errmsg);
            var user =
                (await _userInfoRepository.QueryBySqlAsync("select  top 1* from User_Info where DingtalkToken=@DingtalkToken"
                , new { DingtalkToken = rsp.Result.Unionid })).FirstOrDefault();
            if (user == null)
                throw new Exception("未找到用户信息，请确定是否存在该用户");
            return user;
        }


        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)
                throw new Exception("获取钉钉用户信息失败：" + rsp.Errmsg);
            return rsp.Result.Userid;
        }

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

                //钉钉获取用户Id
                string ddUserId = await GetDingDingUserIdAsPhone(info.Phone);
                var dduser = await GetDingDingUserAsUserId(ddUserId);
                var user = new DingDingUserInfo
                {
                    UserId = ddUserId,
                    DepId = dduser.DeptIdList[0],
                    UnionId = dduser.Unionid

                };
                userStr = Newtonsoft.Json.JsonConvert.SerializeObject(user);
                await _cache.SetStringAsync(key, userStr);
            }

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

        /// <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;
        }
        public Client CreateClient()
        {
            AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config();
            config.Protocol = "https";
            config.RegionId = "central";
            return new Client(config);
        }

        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;
        }

        public GetUploadInfoResponseBody.GetUploadInfoResponseBodyStsUploadInfo GetUpdateOSSFile(string token, string filePath, string fileName, string spaceId, string UnionId)
        {
            //文件长度
            long fileLength = new System.IO.FileInfo(filePath).Length;
            string md5 = GetFileMD5(filePath);
            Client client = CreateClient();
            GetUploadInfoHeaders getUploadInfoHeaders = new GetUploadInfoHeaders();
            getUploadInfoHeaders.XAcsDingtalkAccessToken = token;

            GetUploadInfoRequest getUploadInfoRequest = new GetUploadInfoRequest
            {
                UnionId = UnionId,
                FileName = fileName,
                FileSize = fileLength,
                Md5 = md5,
                AddConflictPolicy = "autoRename",
            };

            var result = client.GetUploadInfoWithOptions(spaceId, "0", getUploadInfoRequest, getUploadInfoHeaders, new AlibabaCloud.TeaUtil.Models.RuntimeOptions());
            return result.Body.StsUploadInfo;
        }



        public static string GetFileMD5(string filePath)
        {
            using (FileStream fs = new FileStream(filePath, FileMode.Open))
            {
                System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] bytes = md5.ComputeHash(fs);

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < bytes.Length; i++)
                {
                    sb.Append(bytes[i].ToString("x2"));
                }
                return sb.ToString();
            }
        }

        public string UpdateS2(string filepath, string fileName, string token)
        {
            long fileSize = new System.IO.FileInfo(filepath).Length;
            string url = $"https://oapi.dingtalk.com/file/upload/single?access_token={token}&file_size={fileSize}&agent_id=1362321125";
            string b = "--------------------------" + Guid.NewGuid().ToString();
            RestSharp.RestClient restClient = new RestSharp.RestClient();
            RestSharp.RestRequest request = new RestSharp.RestRequest(url, RestSharp.Method.POST);
            request.AddHeader("Cache-Control", "no-cache");
            request.AddHeader("content-type", "multipart/form-data");
            request.AddFile(fileName, filepath, MimeMapping.MimeUtility.GetMimeMapping(filepath));
            var response = restClient.Execute(request);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                var r = Newtonsoft.Json.JsonConvert.DeserializeObject<UpdateResult>(response.Content);
                if (!string.IsNullOrEmpty(r.errmsg) && r.errmsg != "ok")
                    throw new Exception(r.errmsg);
                return r.media_id;
            }
            else
            {
                throw new Exception(response.Content);
            }
        }
        public class UpdateResult
        {
            /// <summary>
            /// 
            /// </summary>
            public int errcode { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string errmsg { get; set; }
            /// <summary>
            /// 
            /// </summary>
            public string media_id { get; set; }
        }
        public byte[] GetFieldValue(String fieldName, string boundary, String filename, String contentType, Byte[] fileBytes)
        {
            Encoding encoding = Encoding.UTF8;
            string end = "\r\n";
            string httpRow = "--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
            string httpRowData = String.Format(httpRow, fieldName, filename, contentType);

            byte[] headerBytes = encoding.GetBytes(httpRowData);
            byte[] endBytes = encoding.GetBytes(end);
            byte[] fileDataBytes = new byte[headerBytes.Length + fileBytes.Length + endBytes.Length];

            headerBytes.CopyTo(fileDataBytes, 0);
            fileBytes.CopyTo(fileDataBytes, headerBytes.Length);
            endBytes.CopyTo(fileDataBytes, headerBytes.Length + fileBytes.Length);

            return fileDataBytes;
        }

        public async Task<string> UpdateFile(string filePath, string fileName)
        {
            string token = await GetTokenAsCache();
            IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/media/upload?type=file");
            OapiMediaUploadRequest req = new OapiMediaUploadRequest();
            req.Media = new Top.Api.Util.FileItem(fileName, System.IO.File.ReadAllBytes(filePath));
            req.Type = "file";
            OapiMediaUploadResponse rsp = client.Execute(req, token);
            if (rsp.IsError)
                throw new Exception(rsp.Errmsg);
            return rsp.MediaId;
        }

        /// <summary>
        /// 获取钉盘Id
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<long> GetSpaceId(string userId)
        {
            string token = await GetTokenAsCache();
            IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/processinstance/cspace/info");
            OapiProcessinstanceCspaceInfoRequest req = new OapiProcessinstanceCspaceInfoRequest();
            req.UserId = userId;
            OapiProcessinstanceCspaceInfoResponse rsp = client.Execute(req, token);
            if (rsp.IsError)
                throw new Exception(rsp.Errmsg);
            return rsp.Result.SpaceId;
        }

        public class DentryInfo
        {
            public string Id
            {
                get; set;
            }

            public string extension
            {
                get; set;
            }
            public string name
            {
                get; set;
            }

            public string size
            {
                get; set;
            }
        }

        public async Task<CspaceFile> UpdateFileToCspace(DingDingUserInfo user, string fileName, string filePath)
        {
            string token = await GetTokenAsCache();
            long space_id = await GetSpaceId(user.UserId);
            string mediaId = UpdateS2(filePath, fileName, token);

            AddFileHeaders addFileHeaders = new AddFileHeaders();
            addFileHeaders.XAcsDingtalkAccessToken = token;
            var addFileRequest = new AddFileRequest()
            {
                ParentId = "0",
                UnionId = user.UnionId,
                AddConflictPolicy = "autoRename",
                FileName = fileName,
                FileType = "file",
                MediaId = mediaId
            };
            var client = CreateClient();
            var response = client.AddFileWithOptions(space_id.ToString(), addFileRequest, addFileHeaders, new AlibabaCloud.TeaUtil.Models.RuntimeOptions());
            CspaceFile file = new CspaceFile
            {
                fileId = response.Body.FileId,
                fileName = response.Body.FileName,
                fileSize = response.Body.FileSize.ToString(),
                fileType = response.Body.FileExtension,
                spaceId = response.Body.SpaceId
            };
            return file;

        }

        private static void UpdateOOSFile(string filePath, GetUploadInfoResponseBody.GetUploadInfoResponseBodyStsUploadInfo body)
        {
            var credentialsProvider = new DefaultCredentialsProvider(new DefaultCredentials("LTAIQRzkWSWK7QAY", "lqVlqhPOZfUGw83h9cnIIPnldNvR4s", String.Empty));
            ClientConfiguration clientConfiguration = new ClientConfiguration();
            clientConfiguration.Protocol = Protocol.Https; // 注意, 需要是HTTPS
            var client = new OssClient("https://oss-cn-hongkong.aliyuncs.com", credentialsProvider, clientConfiguration);
            using (FileStream stream = new FileStream(filePath, FileMode.Open))
            {
                var response = client.PutObject("label", body.MediaId, stream);
            }
        }
        public async Task<string> RefuseDingTalk(string code, string msg, long taskId)
        {
            string token = await GetTokenAsCache();
            IDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/process/instance/execute");
            OapiProcessinstanceExecuteV2Request req = new OapiProcessinstanceExecuteV2Request();
            req.Request_ = new OapiProcessinstanceExecuteV2Request.ExecuteTaskRequestDomain
            {
                ProcessInstanceId = code,
                TaskId = taskId,
                Result = "refuse",
                Remark = msg,
                ActionerUserid = DefaultUserId.UserId
            };
            var rsp = client.Execute(req, token);
            string errorMsg = Newtonsoft.Json.JsonConvert.SerializeObject(rsp);
            return errorMsg ?? "成功";
        }

    }


    public class CspaceFile
    {
        public string spaceId
        {
            get; set;
        }

        public string fileName
        {
            get; set;
        }

        public string fileSize
        {
            get; set;
        }

        public string fileType
        {
            get; set;
        }

        public string fileId
        {
            get; set;
        }
    }
}