using System;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Json;
using Com.Bocom.OpenApi.Security.Sign;
using System.Collections.Generic;
using System.Linq;
using Org.BouncyCastle.Asn1.Crmf;

namespace Com.Bocom.OpenApi
{
    namespace Utils
    {
        public class ApiUtils
        {
            public static Object ParseNotifyJsonWithBocomSign(string notifyStr, string charset, string APIGW_PUBLIC_KEY,
                Type T)
            {
                string bizContentStr;
                string sign;
                try
                {
                    int indexOfRootStart = notifyStr.IndexOf(BocomConstants.NOTIFY_BIZ_CONTENT)
                                           + BocomConstants.NOTIFY_BIZ_CONTENT.Length + 2;
                    int indexOfRootEnd = notifyStr.LastIndexOf(",");
                    int indexOfSignStart =
                        notifyStr.LastIndexOf(BocomConstants.SIGN + "\"") + BocomConstants.SIGN.Length + 3;
                    int indexOfSignEnd = notifyStr.LastIndexOf("\"");
                    bizContentStr = notifyStr.Substring(indexOfRootStart, indexOfRootEnd - indexOfRootStart);
                    sign = notifyStr.Substring(indexOfSignStart, indexOfSignEnd - indexOfSignStart);
                }
                catch (Exception e)
                {
                    throw new Exception("notify_biz_content is not format json. notifyStr :\n" + notifyStr, e);
                }

                Boolean passed = RSASignature.Verify(bizContentStr, APIGW_PUBLIC_KEY, charset, sign);
                if (!passed)
                {
                    throw new Exception("Bocom sign verify not passed.");
                }

                try
                {
                    //反序列化并返回
                    BocomResponse response;
                    MemoryStream ms1 = new MemoryStream(Encoding.GetEncoding(charset).GetBytes(bizContentStr));
                    using (MemoryStream ms = new MemoryStream(Encoding.GetEncoding(charset).GetBytes(bizContentStr)))
                    {
                        DataContractJsonSerializer deseralizer = new DataContractJsonSerializer(T);
                        response = (BocomResponse)deseralizer.ReadObject(ms) as BocomResponse;
                    }

                    return response;
                }
                catch (Exception e)
                {
                    throw new Exception("notify_biz_content can not transform to defined class. response: " + notifyStr
                                                                                                            + " defined class name: " +
                                                                                                            T, e);
                }
            }

            public static WriteOffResultNotify ParseCommunicationJsonWithBocomSign(string respStr, string charset, string MY_PRIVATE_KEY, string APIGW_PUBLIC_KEY)
            {
                string bizContentStr;
                string sign;
                try
                {
                    int indexOfRootStart = respStr.IndexOf(BocomConstants.BIZ_CONTENT) + BocomConstants.BIZ_CONTENT.Length + 2;
                    int indexOfRootEnd = respStr.LastIndexOf(",");
                    int indexOfSignStart = respStr.LastIndexOf(BocomConstants.SIGN + "\"") + BocomConstants.SIGN.Length + 3;
                    int indexOfSignEnd = respStr.LastIndexOf("\"");
                    bizContentStr = respStr.Substring(1, indexOfRootEnd - 1);
                    sign = respStr.Substring(indexOfSignStart, indexOfSignEnd - indexOfSignStart);
                }
                catch (Exception e)
                {
                    throw new Exception("response is not format json. respStr :\n" + respStr, e);
                }

                Boolean passed = BocomSignature.Verify(BocomConstants.ENCRYPT_TYPE_RSA_AND_AES, bizContentStr, APIGW_PUBLIC_KEY, charset, sign);
                if (!passed)
                {
                    throw new Exception("Bocom sign verify not passed.");
                }

                try
                {
                    var jsonDic = Kivii.Text.JsonSerializer.DeserializeFromString<Dictionary<string, string>>(respStr);
                    var encryptKeyEncrypt = jsonDic["encrypt_key"];
                    var reqBizContentEncrypt = jsonDic["biz_content"];
                    var encryptKey = BocomEncrypt.AsymmetricalDecrypt(encryptKeyEncrypt, BocomConstants.ENCRYPT_TYPE_RSA_AND_AES, MY_PRIVATE_KEY, charset);
                    var reqBizContent = BocomEncrypt.SymmetricalDecrypt(reqBizContentEncrypt, BocomConstants.ENCRYPT_TYPE_RSA_AND_AES, encryptKey, charset);
                    var rtns = new WriteOffResultNotify();
                    rtns.encrypt_key = encryptKey;
                    rtns.msg_id = jsonDic["msg_id"];
                    rtns.timestamp = jsonDic["timestamp"];
                    rtns.sign = sign;
                    rtns.biz_content = Kivii.Text.JsonSerializer.DeserializeFromString<WriteOffBizContent>(reqBizContent);
                    rtns["encrypt_key"] = encryptKey;
                    rtns["biz_content"] = reqBizContent;
                    rtns["msg_id"] = jsonDic["msg_id"];
                    rtns["timestamp"] = jsonDic["timestamp"];
                    rtns["sign"] = sign;
                    return rtns;
                }
                catch (Exception e)
                {
                    throw new Exception("Bocom decrypt not success.", e);
                }
            }

            public static WriteOffResultNotify ParseCommunicationJsonWithBocomSign(Dictionary<string, string> respStr, string charset, string MY_PRIVATE_KEY, string APIGW_PUBLIC_KEY)
            {
                string biz_content = respStr["biz_content"];
                string msg_id = respStr["msg_id"];
                string timestamp = respStr["timestamp"];
                string encrypt_key = respStr["encrypt_key"];
                string sign = respStr["sign"];
                var notify = new WriteOffBizContentObj();
                notify.biz_content = biz_content;
                notify.msg_id = msg_id;
                notify.timestamp = timestamp;
                notify.encrypt_key = encrypt_key;
                var biz_contentStr = Kivii.Text.JsonSerializer.SerializeToString(notify);
                biz_contentStr = biz_contentStr.Replace("{", "");
                biz_contentStr = biz_contentStr.Replace("}", "");
                Boolean passed = BocomSignature.Verify(BocomConstants.ENCRYPT_TYPE_RSA_AND_AES, biz_contentStr, APIGW_PUBLIC_KEY, charset, sign);
                if (!passed)
                {
                    throw new Exception("Bocom sign verify not passed.");
                }

                try
                {
                    //var jsonDic = Kivii.Text.JsonSerializer.DeserializeFromString<Dictionary<string, string>>(respStr);
                    var encryptKeyEncrypt = encrypt_key;
                    var reqBizContentEncrypt = biz_content;
                    var encryptKey = BocomEncrypt.AsymmetricalDecrypt(encryptKeyEncrypt, BocomConstants.ENCRYPT_TYPE_RSA_AND_AES, MY_PRIVATE_KEY, charset);
                    var reqBizContent = BocomEncrypt.SymmetricalDecrypt(reqBizContentEncrypt, BocomConstants.ENCRYPT_TYPE_RSA_AND_AES, encryptKey, charset);
                    var rtns = new WriteOffResultNotify();
                    rtns.encrypt_key = encryptKey;
                    rtns.msg_id = msg_id;
                    rtns.timestamp = timestamp;
                    rtns.sign = sign;
                    rtns.biz_content = Kivii.Text.JsonSerializer.DeserializeFromString<WriteOffBizContent>(reqBizContent);
                    rtns["encrypt_key"] = encryptKey;
                    rtns["biz_content"] = reqBizContent;
                    rtns["msg_id"] = msg_id;
                    rtns["timestamp"] = timestamp;
                    rtns["sign"] = sign;
                    return rtns;
                }
                catch (Exception e)
                {
                    throw new Exception("Bocom decrypt not success.", e);
                }
            }

            public static object SignRspBizContent(string rspBizContent, string encrypt_key, string mY_PRIVATE_KEY)
            {
                var rspContent = BocomEncrypt.SymmetricalEncrypt(rspBizContent, BocomConstants.ENCRYPT_TYPE_RSA_AND_AES, encrypt_key, "UTF-8");
                string signContent;
                try
                {
                    signContent = BocomSignature.Sign(BocomConstants.ENCRYPT_TYPE_RSA_AND_AES, rspContent, mY_PRIVATE_KEY, "UTF-8");
                }
                catch (Exception ex)
                {
                    throw new BocomApiException($"Bocom sign not success.{ex.Message}");
                }
                string newBody = "{\"rsp_biz_content\":\"" + rspContent + "\",\"sign\":\"" + signContent + "\"}";
                return newBody;
            }
        }
    }
}