package video_decrypt

import (
	"errors"
	"fmt"
	"hash/crc32"
	"io"
	"math/rand"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"sync"
)

type transport struct {
	http.RoundTripper
	key string
}

type handle struct {
	host        string
	port        int
	reverseUrl  string
	reverseHost string
}

type bodyWrapper struct {
	body io.ReadCloser
	key  string
}

func (b bodyWrapper) Read(p []byte) (int, error) {
	n, err := b.body.Read(p)
	if err != io.EOF && err != nil {
		return n, err
	}

	buf, decErr := decryptDataV2(p, b.key)
	if decErr != nil {
		return 0, decErr
	}

	copy(p, buf)

	return n, err
}

func (b bodyWrapper) Close() error {
	b.body.Close()
	return nil
}

const EncryptKeyLen = 14

var freePort = 0
var isStart = false
var cacheMap = sync.Map{}

func GetHostPath() string {
	return fmt.Sprintf("http://127.0.0.1:%d", freePort)
}

//启动服务器
func StartServer(reverseUrl, reverseHost string) error {
	if isStart {
		return nil
	}

	freePortTmp, err := getFreePort(7003, 8000)
	if err != nil {
		return err
	}

	freePort = freePortTmp

	h := &handle{host: "127.0.0.1", port: freePort, reverseUrl: reverseUrl, reverseHost: reverseHost}

	addr := fmt.Sprintf("0.0.0.0:%d", freePort)

	fmt.Println("start server:" + addr)

	go func() {
		_ = http.ListenAndServe(addr, h)
	}()

	isStart = true
	return nil
}

func getFreePort(min, max int) (int, error) {
	for i := min; i <= max; i++ {
		if portIsFree(i) {
			return i, nil
		}
	}

	return 0, errors.New("没有可用端口")
}

func portIsFree(checkPort int) bool {
	addr, err := net.ResolveTCPAddr("tcp", fmt.Sprintf("localhost:%d", checkPort))
	if err != nil {
		return false
	}

	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		return false
	}

	defer l.Close()
	return true
}

func (t *transport) RoundTrip(req *http.Request) (resp *http.Response, err error) {
	defer func() {
		_ = recover()
	}()

	resp, err = t.RoundTripper.RoundTrip(req)
	if err != nil {
		return nil, err
	}

	body := bodyWrapper{
		body: resp.Body,
		key:  req.Header.Get("enc_key"),
	}

	resp.Body = body
	return resp, nil
}

//启动反向代理
func (server *handle) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	remote, err := url.Parse(server.reverseUrl)
	if err != nil {
		panic(err)
	}

	key := r.Header.Get("enc_key")
	r.Host = server.reverseHost
	proxy := httputil.NewSingleHostReverseProxy(remote)
	proxy.Transport = &transport{
		RoundTripper: http.DefaultTransport,
		key:          key,
	}

	proxy.ServeHTTP(w, r)
}

//加密数据
func EncryptData(data []byte, key string) ([]byte, error) {
	if len(key) != EncryptKeyLen {
		return nil, errors.New("key长度要14个字符")
	}

	dataLen := len(data)
	if dataLen == 0 {
		return data, nil
	}

	sortTable := getSortTable(stringHash(key))
	result := make([]byte, dataLen)

	for i := 0; i < dataLen; i++ {
		item := data[i]
		result[i] = sortTable[item]
	}

	return result, nil
}

//解密数据
func decryptData(data []byte, key string) ([]byte, error) {
	if len(key) != EncryptKeyLen {
		return nil, errors.New("key长度要14个字符")
	}

	dataLen := len(data)
	if dataLen == 0 {
		return data, nil
	}

	sortTable := getSortTable(stringHash(key))
	decTable := make([]byte, 0x100)

	//解密表，就是key和item互換一下
	for i := 0; i < 0x100; i++ {
		decTable[sortTable[i]] = byte(i)
	}

	result := make([]byte, dataLen)

	for i := 0; i < dataLen; i++ {
		item := data[i]
		result[i] = decTable[item]
	}

	return result, nil
}

func decryptDataV2(data []byte, key string) ([]byte, error) {
	if len(key) == 0 {
		return nil, errors.New("key长度不能为空")
	}

	dataLen := len(data)
	if dataLen == 0 {
		return data, nil
	}

	sortTable := getSortTableDecV2(key)
	result := make([]byte, dataLen)

	for i := 0; i < dataLen; i++ {
		item := int(data[i])
		result[i] = byte(sortTable[item])
	}

	return result, nil
}

func getSortTableDecV2(key string) map[int]int {
	mapTable := getSortTableV2(key)
	mapTableDec := map[int]int{}

	for key, val := range mapTable {
		mapTableDec[val] = key
	}

	return mapTableDec
}

func getSortTableV2(key string) map[int]int {
	mapTable := map[int]int{}
	for i := 0; i <= 0xff; i++ {
		mapTable[i] = i
	}

	bytes := []byte(key)

	for i := 0; i < 0xff; i++ {
		val := randNum(bytes, i+10, i+1, 0xff+1)

		tmpVal := mapTable[val]

		mapTable[val] = mapTable[i]
		mapTable[i] = tmpVal
	}

	return mapTable
}

func randNum(bytes []byte, index, start, end int) int {
	total := 0
	for _, item := range bytes {
		total += int(item) + index
	}

	if total < 0 {
		total = total * -1
	}

	result := start + (total % (end - start))
	return result
}

//加密排序的表
func getSortTable(keyHash int32) []byte {
	loadedMap, ok := cacheMap.Load(keyHash)
	if ok {
		return loadedMap.([]byte)
	}

	curRand := rand.New(rand.NewSource(int64(keyHash)))
	length := 0x100

	//生成256长度的原始數組
	baseAry := make([]byte, length)
	for i := 1; i <= 0xff-1; i++ {
		baseAry[i] = byte(i)
	}

	baseAry[0] = 0xff
	baseAry[0xff] = 0

	//隨機數組
	randAry := make([]byte, length)

	//打亂排序
	for i := 0; i < length; i++ {
		index := curRand.Intn(length - i)
		randAry[i] = baseAry[index]
		baseAry[index] = baseAry[length-i-1]
	}

	cacheMap.Store(keyHash, randAry)
	return randAry
}

func stringHash(s string) int32 {
	v := int32(crc32.ChecksumIEEE([]byte(s)))
	if v >= 0 {
		return v
	}
	if -v >= 0 {
		return -v
	}

	return 0
}
