package tonglianpayapi

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"fmt"
	"git.rosy.net.cn/baseapi/platformapi"
	"git.rosy.net.cn/baseapi/utils"
	"net/http"
	"sort"
	"strings"
)

const (
	//RSA私钥(非JAVA适用)
	RSAPrivateKeyNotJava = `MIIEpAIBAAKCAQEAx9qhvqwyZ5hUKoxErxjgOgpjipbmJr20tGCtd/7UXCksVE9S/JWF6+LuT9jKAQpDDU4Dniu5mpwp6vfz2S7D51bO+S2mmSyiV6//NHpWZJwP9Lsb2fbU0tJUNiXGx3P79sA7ZDi5hkho59CX+tOr/gVDKXTb4Rbyj50+N+Rxt3i/Kd4Sf8AMRodP4SxcOjS4pbmwLFcD5H35czvXSRBQkHAptJ6keiYJLmi2ylsLWnBgf0BZYp04i5EVxiUT389ji7WNOUpNedb3wjOio877VatNm4XIZx0BFZVF8ZFEzEJkVXRAxRlR71nl1uKpNPVqfPQZ8pY3RrUmCxOwnJl5vQIDAQABAoIBAB3U4jjabkmtYL7bIjN6xJmVTGd2/9K/lXYpSitzs9Iv6SiKkKoYTZ24yXbMttZx6DFXuE2HXFSaQ92JdnIwO1jQSePC7y/FDFSHdlIogrXQ38bZmR4vbHQtphlRCTtjcjRSXGso1nSXYWVc6xqrNuybb3uEMIAIU1uhjpR8Ooc2sMfmpNdqCS5SKngIsRj5FQZzBPUoBiAlKiYck/UJzUgdVyxz5hpaFqB2V6VciD3E/PSa6OtSTPVO7a1KUD1rmvADZTmAYSqYwRBqZxkb42MNDtOW8YqRFC/rTlSQOo76XvT0AGSY2ZvFC89LrIZc9hF76k8OfCi8XjrwrMKgbpcCgYEA6/WiwthWy41Ch9R9xCubkPYfulNjq9CKbYyWnmmARnnhM5iRYJidqyfw1IbSVVm9Qy3o3VBnYocOTRJUTmOmpQgWqI4t/HjCZiFZeKF30F9ytl1urCbkXYWA2lygf2ZUYiCt3/CNC0bct4nZa42sGu3TXYZKcpVqlZT6tWywu8sCgYEA2NP4Zz5zJGzskhVdsEJbL7ttv/yX7X/g6AW3IhcI108bWfoA+i6YjbDsC8aftgIHPheaW/6n+oirDwoYdgrWa2/eCIKBo5uchtDmUb8qIXog1RbryKqOevLDkGRlJ8NAOIZfGwjT3pfhbtM+wvH5PCFBywoMlxz2sWZ2x4Vzf5cCgYEAza8Jeh9rSXSRkiXAm8gHi42AisM2FwdqI6RxhxUgJE8J6BgOYc2nYxMl85yyrIPVX0Idww3bkR95b+WSZ+Kl2SX72mJV48bAbpaTj3vxHUqWjDFVz+r3Fi7R64biwStKU195McRWroXO0I7xX7fXVoIJxXTSYJ+ukUWUZaGhTZECgYEAuHv6IVYYP8jRrCWztjFvRniRk8VGOxQP9zpNrBqvMgqjufWl+TfGIuCCpi5UW1b0dJc+hcFxiQ/Zg41SbLUh5P2ki9cGmH7hOi/pl2owXZV88/FxoiXD3sZJMMTK8H8HWFC0ANuM8RqG+3WPM+0P42JkiW2+cqB5IU2OCIr6T3cCgYBSLkui8zbMJB0TfE+KGxdm3e+sX26ZE2ZqQmTfJoRcxGgkWC7oY8HdIwws1uFeO38C5SMkkT8YlJghAjIIsfIUuCWQc5tBwvcb5f78/iJRUVgHXl3dH+9HvJKh/I4NeTIX6NTlaOrkUjgnkLLWbU7+b+3SCsVnvKH7uEm5cH0Ejg==`
	//RSA公钥
	RSAPublicKey = `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx9qhvqwyZ5hUKoxErxjgOgpjipbmJr20tGCtd/7UXCksVE9S/JWF6+LuT9jKAQpDDU4Dniu5mpwp6vfz2S7D51bO+S2mmSyiV6//NHpWZJwP9Lsb2fbU0tJUNiXGx3P79sA7ZDi5hkho59CX+tOr/gVDKXTb4Rbyj50+N+Rxt3i/Kd4Sf8AMRodP4SxcOjS4pbmwLFcD5H35czvXSRBQkHAptJ6keiYJLmi2ylsLWnBgf0BZYp04i5EVxiUT389ji7WNOUpNedb3wjOio877VatNm4XIZx0BFZVF8ZFEzEJkVXRAxRlR71nl1uKpNPVqfPQZ8pY3RrUmCxOwnJl5vQIDAQAB`

	//RSA私钥(JAVA适用)
	RSAPrivateKeyJava = `MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDH2qG+rDJnmFQqjESvGOA6CmOKluYmvbS0YK13/tRcKSxUT1L8lYXr4u5P2MoBCkMNTgOeK7manCnq9/PZLsPnVs75LaaZLKJXr/80elZknA/0uxvZ9tTS0lQ2JcbHc/v2wDtkOLmGSGjn0Jf606v+BUMpdNvhFvKPnT435HG3eL8p3hJ/wAxGh0/hLFw6NLilubAsVwPkfflzO9dJEFCQcCm0nqR6JgkuaLbKWwtacGB/QFlinTiLkRXGJRPfz2OLtY05Sk151vfCM6KjzvtVq02bhchnHQEVlUXxkUTMQmRVdEDFGVHvWeXW4qk09Wp89BnyljdGtSYLE7CcmXm9AgMBAAECggEAHdTiONpuSa1gvtsiM3rEmZVMZ3b/0r+VdilKK3Oz0i/pKIqQqhhNnbjJdsy21nHoMVe4TYdcVJpD3Yl2cjA7WNBJ48LvL8UMVId2UiiCtdDfxtmZHi9sdC2mGVEJO2NyNFJcayjWdJdhZVzrGqs27Jtve4QwgAhTW6GOlHw6hzawx+ak12oJLlIqeAixGPkVBnME9SgGICUqJhyT9QnNSB1XLHPmGloWoHZXpVyIPcT89Jro61JM9U7trUpQPWua8ANlOYBhKpjBEGpnGRvjYw0O05bxipEUL+tOVJA6jvpe9PQAZJjZm8ULz0ushlz2EXvqTw58KLxeOvCswqBulwKBgQDr9aLC2FbLjUKH1H3EK5uQ9h+6U2Or0IptjJaeaYBGeeEzmJFgmJ2rJ/DUhtJVWb1DLejdUGdihw5NElROY6alCBaoji38eMJmIVl4oXfQX3K2XW6sJuRdhYDaXKB/ZlRiIK3f8I0LRty3idlrjawa7dNdhkpylWqVlPq1bLC7ywKBgQDY0/hnPnMkbOySFV2wQlsvu22 //Jftf+DoBbciFwjXTxtZ+gD6LpiNsOwLxp+2Agc+F5pb/qf6iKsPChh2CtZrb94IgoGjm5yG0OZRvyoheiDVFuvIqo568sOQZGUnw0A4hl8bCNPel+Fu0z7C8fk8IUHLCgyXHPaxZnbHhXN/lwKBgQDNrwl6H2tJdJGSJcCbyAeLjYCKwzYXB2ojpHGHFSAkTwnoGA5hzadjEyXznLKsg9VfQh3DDduRH3lv5ZJn4qXZJfvaYlXjxsBulpOPe/EdSpaMMVXP6vcWLtHrhuLBK0pTX3kxxFauhc7QjvFft9dWggnFdNJgn66RRZRloaFNkQKBgQC4e/ohVhg/yNGsJbO2MW9GeJGTxUY7FA/3Ok2sGq8yCqO59aX5N8Yi4IKmLlRbVvR0lz6FwXGJD9mDjVJstSHk/aSL1waYfuE6L+mXajBdlXzz8XGiJcPexkkwxMrwfwdYULQA24zxGob7dY8z7Q/jYmSJbb5yoHkhTY4IivpPdwKBgFIuS6LzNswkHRN8T4obF2bd76xfbpkTZmpCZN8mhFzEaCRYLuhjwd0jDCzW4V47fwLlIySRPxiUmCECMgix8hS4JZBzm0HC9xvl/vz+IlFRWAdeXd0f70e8kqH8jg15Mhfo1OVo6uRSOCeQstZtTv5v7dIKxWe8ofu4SblwfQSO`
	//SM2公钥
	SM2PublicKey = `MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE7yCR6yp3jPOgBTqWqE9D3ugudcsi4epjq3EJ6mq3Y0nrR489Pld7V5yk+QuH2SUZMFmu46/adlnN/+cd496lkg==`
	//SM2私钥
	SM2PrivateKey = `MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg1Rj + skv1B3dGwe2wGy9OF6N4vqxAGM44MR6e2kWTxhegCgYIKoEcz1UBgi2hRANCAATvIJHrKneM86AFOpaoT0Pe6C51yyLh6mOrcQnqardjSetHjz0 + V3tXnKT5C4fZJRkwWa7jr9p2Wc3/5x3j3qWS`
	// 测试私钥
	cusRsaPrivateTestKey = `MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJgHMGYsspghvP+yCbjLG43CkZuQ3YJyDcmEKxvmgblITfmiTPx2b9Y2iwDT9gnLGExTDm1BL2A8VzMobjaHfiCmTbDctu680MLmpDDkVXmJOqdlXh0tcLjhN4+iDA2KkRqiHxsDpiaKT6MMBuecXQbJtPlVc1XjVhoUlzUgPCrvAgMBAAECgYAV9saYTGbfsdLOF5kYo0dve1JxaO7dFMCcgkV+z2ujKtNmeHtU54DlhZXJiytQY5Dhc10cjb6xfFDrftuFcfKCaLiy6h5ETR8jyv5He6KH/+X6qkcGTkJBYG1XvyyFO3PxoszQAs0mrLCqq0UItlCDn0G72MR9/NuvdYabGHSzEQJBAMXB1/DUvBTHHH4LiKDiaREruBb3QtP72JQS1ATVXA2v6xJzGPMWMBGQDvRfPvuCPVmbHENX+lRxMLp39OvIn6kCQQDEzYpPcuHW/7h3TYHYc+T0O6z1VKQT2Mxv92Lj35g1XqV4Oi9xrTj2DtMeV1lMx6n/3icobkCQtuvTI+AcqfTXAkB6bCz9NwUUK8sUsJktV9xJN/JnrTxetOr3h8xfDaJGCuCQdFY+rj6lsLPBTnFUC+Vk4mQVwJIE0mmjFf22NWW5AkAmsVaRGkAmui41Xoq52MdZ8WWm8lY0BLrlBJlvveU6EPqtcZskWW9KiU2euIO5IcRdpvrB6zNMgHpLD9GfMRcPAkBUWOV/dH13v8V2Y/Fzuag/y5k3/oXi/WQnIxdYbltad2xjmofJ7DbB7MJqiZZD8jlr8PCZPwRNzc5ntDStc959`

	// 回调地址
	OnlinePayCallbackUrl = "https://callback.jxc4.com/tongLian/onLinePay"
	// 接口地址
	OnlinePayUrl           = `https://vsp.allinpay.com/apiweb/unitorder/scanqrpay` // 扫码支付
	OnLineTransactionQuery = `https://vsp.allinpay.com/apiweb/tranx/query`         // 交易查询,查询订单的支付状态
	OnLineRefund           = `https://vsp.allinpay.com/apiweb/tranx/refund`        // 同一退款接口
	OnLineAddTerm          = `https://vsp.allinpay.com/cusapi/merchantapi/addterm` // 添加设备终端
	OnLineQuerYTerm        = `https://vsp.allinpay.com/cusapi/merchantapi/qryterm` // 查询设备终端
)

const (
	EncryptionRsa           = "RSA" // 加密方式
	ScannerOperrationStart  = "00"  // 扫码枪本次操作类型-新增
	ScannerOperrationLogOff = "02"  // 扫码枪本次操作类型-注销
	ScannerOperrationUpdate = "01"  // 扫码枪本次操作类型-修改
)

var (
	TransactionStatus = map[string]string{
		"0000": "交易成功",
		"1001": "交易不存在",
		"2008": "交易处理中,请查询交易,如果是实时交易(例如刷卡支付,交易撤销,退货),建议每隔一段时间(10秒)查询交易",
		"2000": "交易处理中,请查询交易,如果是实时交易(例如刷卡支付,交易撤销,退货),建议每隔一段时间(10秒)查询交易",
		"3888": "流水号重复",
		"3099": "渠道商户错误",
		"3014": "交易金额小于应收手续费",
		"3031": "校验实名信息失败",
		"3088": "交易未支付",
		"3089": "撤销异常,如已影响资金24小时内会做差错退款处理",
		"3050": "交易已被撤销",
		"3999": "1",
		"3889": "1",
		"3045": "1",
	}
)

// CreateOnlineBankOrder 网银创建订单(扫码枪,扫二维码支付)
func (a *API) CreateOnlineBankOrder(param *OnlinePayParam) (statusCode, trxid, errRemake string, err error) {
	onlineReq := utils.Struct2Map(param, "", false)
	result, err := a.AccessAPI2(OnlinePayUrl, onlineReq)
	if err != nil {
		return "", "", "", err
	}
	// 请求接口成功后通联系统返回JSON字符串数据，把除sign之外的其他所有非空字段组成键值对，进行同样的排序和组装处理，并用通联的公钥进行验签
	// 暂时不考虑验签

	if result["retcode"].(string) != "SUCCESS" {
		return "", "", "", fmt.Errorf(result["retmsg"].(string))
	}

	payInfo := &OnlinePayRetMsg{}
	if err = utils.Map2StructByJson(result, payInfo, true); err != nil {
		return "", "", "", err
	}

	return payInfo.Trxstatus, payInfo.Trxid, payInfo.Errmsg, nil
}

// QueryPayTransaction 订单交易状态查询
func (a *API) QueryPayTransaction(param *PayTransactionStatusQuery) (statusCode, errRemake string, err error) {
	onlineReq := utils.Struct2Map(param, "", false)
	result, err := a.AccessAPI2(OnLineTransactionQuery, onlineReq)
	if err != nil {
		return "", "", err
	}
	if result["retcode"].(string) != "SUCCESS" {
		return "", "", fmt.Errorf(result["retmsg"].(string))
	}

	payInfo := &PayTransactionStatusResult{}
	if err = utils.Map2StructByJson(result, payInfo, true); err != nil {
		return "", "", err
	}

	return payInfo.Trxstatus, payInfo.Errmsg, nil
}

// OrderRefund 退单
func (a *API) OrderRefund(param *OnLineOrderRefundParam) (statusCode, errRemake string, err error) {
	onlineReq := utils.Struct2Map(param, "", false)
	result, err := a.AccessAPI2(OnLineRefund, onlineReq)
	if err != nil {
		return "", "", err
	}
	if result["retcode"].(string) != "SUCCESS" {
		return "", "", fmt.Errorf(result["retmsg"].(string))
	}

	payInfo := &OnLineOrderRefundResult{}
	if err = utils.Map2StructByJson(result, payInfo, true); err != nil {
		return "", "", err
	}

	return payInfo.Trxstatus, payInfo.Errmsg, nil
}

// TLAddTerm 采集门店终端设备信息
func (a *API) TLAddTerm(param *AddTermReq) error {
	onlineReq := utils.Struct2Map(param, "", false)
	result, err := a.AccessAPI2(OnLineAddTerm, onlineReq)
	if err != nil {
		return err
	}
	if result["retcode"].(string) != "SUCCESS" {
		return fmt.Errorf(result["retmsg"].(string))
	}
	return nil
}

// TLQueryTerm 采集门店终端设备信息查询
func (a *API) TLQueryTerm(param *AddTermQuery) (string, error) {
	onlineReq := utils.Struct2Map(param, "", false)
	result, err := a.AccessAPI2(OnLineQuerYTerm, onlineReq)
	if err != nil {
		return "", err
	}
	if result["retcode"].(string) != "SUCCESS" {
		return "", fmt.Errorf(result["retmsg"].(string))
	}
	return fmt.Sprintf("微信报备:%s,阿里报备:%s", result["wxmsg"].(string), result["almsg"].(string)), nil
}

func (a *API) AccessAPI2(action string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
	params := make(map[string]interface{})
	params["appid"] = a.appID
	params["cusid"] = a.cusID
	if action != OnLineAddTerm {
		params["randomstr"] = utils.GetUUID()
	}
	params["version"] = "12"
	params = utils.MergeMaps(params, bizParams)
	sign, err := a.signParamRSA(params, RSAPrivateKeyNotJava)
	if err != nil {
		return nil, err
	}
	params["sign"] = sign

	err = platformapi.AccessPlatformAPIWithRetry(a.client,
		func() *http.Request {
			request, _ := http.NewRequest(http.MethodPost, action, strings.NewReader(utils.Map2URLValues(params).Encode()))
			request.Header.Set("charset", "UTF-8")
			request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
			return request
		},
		a.config,
		func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
			if jsonResult1 == nil {
				return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
			}
			if err == nil {
				returnCode := utils.Interface2String(jsonResult1["retcode"])
				if returnCode != OnlinePayStatusSuccess {
					errLevel = platformapi.ErrLevelGeneralFail
					err = utils.NewErrorCode(utils.Interface2String(jsonResult1["retcode"])+utils.Interface2String(jsonResult1["retmsg"]), returnCode)
				}
				retVal = jsonResult1
			}
			return errLevel, err
		})
	return retVal, err
}

func (a *API) signParamRSA(params map[string]interface{}, RSAPrivate string) (sig string, err error) {
	decodeString, err := base64.StdEncoding.DecodeString(RSAPrivate)
	if err != nil {
		return "", err
	}

	private, err := x509.ParsePKCS1PrivateKey(decodeString) //之前看java demo中使用的是pkcs8
	if err != nil {
		return "", err
	}

	var valueList []string
	for k, v := range params {
		if k != sigKey {
			if str := fmt.Sprint(v); str != "" {
				valueList = append(valueList, fmt.Sprintf("%s=%s", k, str))
			}
		}
	}
	sort.Sort(sort.StringSlice(valueList))
	context := strings.Join(valueList, "&")
	h := crypto.Hash.New(crypto.SHA1) //进行SHA1的散列
	h.Write([]byte(context))
	hashed := h.Sum(nil)

	// 进行rsa加密签名
	signedData, err := rsa.SignPKCS1v15(rand.Reader, private, crypto.SHA1, hashed)
	if err != nil {
		return "", err
	}

	signData := base64.StdEncoding.EncodeToString(signedData)
	return signData, nil
}
