package mtwmapi

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"errors"
	"io"
	"log"
	"sync"
)

//ip配置信息
type global struct {
	LocalHost      string //本机内网IP
	RemoteHost     string //远程端IP
	RemotePort     string //远程端口
	ServerList     map[string]string
	ServerListLock sync.RWMutex
}
type commonConf struct {
	HttpPort  string
	RPCPort   string
	Cluster   bool
	CryptoKey string
}

var (
	GlobalSetting = &global{}
	CommonSetting = &commonConf{
		HttpPort:  "6000",
		RPCPort:   "7000",
		Cluster:   false,
		CryptoKey: "Adba723b7fe06819",
	}
)

/*
以下为clientID相关逻辑
*/

//对称加密IP和端口，当做clientId
func GenClientId() string {
	raw := []byte(GlobalSetting.LocalHost + ":" + CommonSetting.RPCPort)
	//raw := []byte(hostStr)
	str, err := Encrypt(raw, []byte(CommonSetting.CryptoKey))
	if err != nil {
		log.Fatal(err)
	}
	return str
}

func Encrypt(rawData, key []byte) (string, error) {
	data, err := aesCBCEncrypt(rawData, key)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(data), nil
}

//AES加密
func aesCBCEncrypt(rawData, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return []byte{}, err
	}

	//填充原文
	blockSize := block.BlockSize()

	rawData = pKCS7Padding(rawData, blockSize)
	//初始向量IV必须是唯一，但不需要保密
	cipherText := make([]byte, blockSize+len(rawData))
	//block大小 16
	iv := cipherText[:blockSize]
	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
		return []byte{}, err
	}

	//block大小和初始向量大小一定要一致
	mode := cipher.NewCBCEncrypter(block, iv)
	mode.CryptBlocks(cipherText[blockSize:], rawData)

	return cipherText, nil
}

func DecryptDESECB(d, key []byte) string {
	data, err := base64.StdEncoding.DecodeString(string(d))
	if err != nil {
		return ""
	}
	block, err := aes.NewCipher(key)
	if err != nil {
		return ""
	}
	bs := block.BlockSize()
	if len(data)%bs != 0 {
		return ""
	}
	out := make([]byte, len(data))
	dst := out
	for len(data) > 0 {
		block.Decrypt(dst, data[:bs])
		data = data[bs:]
		dst = dst[bs:]
	}
	out = PKCS5UnPadding(out)
	return string(out)
}
func PKCS5UnPadding(origData []byte) []byte {
	length := len(origData)
	unpadding := int(origData[length-1])
	return origData[:(length - unpadding)]
}

func Decrypt(rawData string, key []byte) (string, error) {
	data, err := base64.StdEncoding.DecodeString(rawData)
	if err != nil {
		return "", err
	}
	dnData, err := aesCBCDncrypt(data, key)
	if err != nil {
		return "", err
	}
	return string(dnData), nil
}

//AES解密
func aesCBCDncrypt(encryptData, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return []byte{}, err
	}

	blockSize := block.BlockSize()

	if len(encryptData) < blockSize {
		return []byte{}, errors.New("ciphertext too short")
	}
	iv := encryptData[:blockSize]
	encryptData = encryptData[blockSize:]

	if len(encryptData)%blockSize != 0 {
		return []byte{}, errors.New("ciphertext is not a multiple of the block size")
	}

	mode := cipher.NewCBCDecrypter(block, iv)

	mode.CryptBlocks(encryptData, encryptData)
	//解填充
	encryptData, err = pKCS7UnPadding(encryptData)
	return encryptData, err
}

func pKCS7Padding(ciphertext []byte, blockSize int) []byte {
	padding := blockSize - len(ciphertext)%blockSize
	padText := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(ciphertext, padText...)
}

func pKCS7UnPadding(origData []byte) ([]byte, error) {
	length := len(origData)
	unPadding := int(origData[length-1])
	if length-unPadding < 0 || length-unPadding > len(origData) {
		return nil, errors.New("unPadding error")
	}

	return origData[:(length - unPadding)], nil
}
