package service

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"qnc-server/app/main/api/internal/config"
	"strings"
	"time"

	"github.com/tidwall/gjson"
)

type YushanService struct {
	config config.YushanConfig
}

func NewYushanService(c config.Config) *YushanService {
	return &YushanService{
		config: c.YushanConfig,
	}
}

func (y *YushanService) request(prodID string, params map[string]interface{}) ([]byte, error) {
	// 获取当前时间戳
	unixMilliseconds := time.Now().UnixNano() / int64(time.Millisecond)

	// 生成请求序列号
	requestSN, _ := y.GenerateRandomString()

	// 构建请求数据
	reqData := map[string]interface{}{
		"prod_id":    prodID,
		"req_time":   unixMilliseconds,
		"request_sn": requestSN,
		"req_data":   params,
	}

	// 将请求数据转换为 JSON 字节数组
	messageBytes, err := json.Marshal(reqData)
	if err != nil {
		return nil, err
	}

	// 获取 API 密钥
	key, err := hex.DecodeString(y.config.ApiKey)
	if err != nil {
		return nil, err
	}

	// 使用 AES CBC 加密请求数据
	cipherText := y.AES_CBC_Encrypt(messageBytes, key)

	// 将加密后的数据编码为 Base64 字符串
	content := base64.StdEncoding.EncodeToString(cipherText)

	// 发起 HTTP 请求
	client := &http.Client{}
	req, err := http.NewRequest("POST", y.config.Url, strings.NewReader(content))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("ACCT_ID", y.config.AcctID)

	// 执行请求
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// 读取响应体
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var respData []byte

	if IsJSON(string(body)) {
		respData = body
	} else {
		sDec, err := base64.StdEncoding.DecodeString(string(body))
		if err != nil {
			return nil, err
		}
		respData = y.AES_CBC_Decrypt(sDec, key)
	}
	retCode := gjson.GetBytes(respData, "retcode").String()

	if retCode == "100000" {
		// retcode 为 100000，表示查询为空
		return nil, fmt.Errorf("羽山请求查空: %s", string(respData))
	} else if retCode == "000000" {
		// retcode 为 000000，表示有数据，返回 retdata
		retData := gjson.GetBytes(respData, "retdata")
		if !retData.Exists() {
			return nil, fmt.Errorf("羽山请求retdata为空: %s", string(respData))
		}
		return []byte(retData.Raw), nil
	} else {
		return nil, fmt.Errorf("羽山请求未知的状态码: %s", string(respData))
	}

}

// 判断字符串是否为 JSON 格式
func IsJSON(s string) bool {
	var js interface{}
	return json.Unmarshal([]byte(s), &js) == nil
}

// GenerateRandomString 生成一个32位的随机字符串订单号
func (y *YushanService) GenerateRandomString() (string, error) {
	// 创建一个16字节的数组
	bytes := make([]byte, 16)
	// 读取随机字节到数组中
	if _, err := rand.Read(bytes); err != nil {
		return "", err
	}
	// 将字节数组编码为16进制字符串
	return hex.EncodeToString(bytes), nil
}

// AEC加密（CBC模式）
func (y *YushanService) AES_CBC_Encrypt(plainText []byte, key []byte) []byte {
	//指定加密算法，返回一个AES算法的Block接口对象
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}
	//进行填充
	plainText = Padding(plainText, block.BlockSize())
	//指定初始向量vi,长度和block的块尺寸一致
	iv := []byte("0000000000000000")
	//指定分组模式，返回一个BlockMode接口对象
	blockMode := cipher.NewCBCEncrypter(block, iv)
	//加密连续数据库
	cipherText := make([]byte, len(plainText))
	blockMode.CryptBlocks(cipherText, plainText)
	//返回base64密文
	return cipherText
}

// AEC解密（CBC模式）
func (y *YushanService) AES_CBC_Decrypt(cipherText []byte, key []byte) []byte {
	//指定解密算法，返回一个AES算法的Block接口对象
	block, err := aes.NewCipher(key)
	if err != nil {
		panic(err)
	}
	//指定初始化向量IV,和加密的一致
	iv := []byte("0000000000000000")
	//指定分组模式，返回一个BlockMode接口对象
	blockMode := cipher.NewCBCDecrypter(block, iv)
	//解密
	plainText := make([]byte, len(cipherText))
	blockMode.CryptBlocks(plainText, cipherText)
	//删除填充
	plainText = UnPadding(plainText)
	return plainText
} // 对明文进行填充
func Padding(plainText []byte, blockSize int) []byte {
	//计算要填充的长度
	n := blockSize - len(plainText)%blockSize
	//对原来的明文填充n个n
	temp := bytes.Repeat([]byte{byte(n)}, n)
	plainText = append(plainText, temp...)
	return plainText
}

// 对密文删除填充
func UnPadding(cipherText []byte) []byte {
	//取出密文最后一个字节end
	end := cipherText[len(cipherText)-1]
	//删除填充
	cipherText = cipherText[:len(cipherText)-int(end)]
	return cipherText
}
