package service

import (
	"fmt"
	"math/rand"
	"strconv"
	"time"
)

const (
	_bits    = uint64(4)
	_splitOn = 32 / _bits
)

var (
	table = []uint64{
		0x4f3a97cb, 0x8ae2d379, 0xe8df369a, 0x5ac82647, 0xcdaf6987, 0xabd28536, 0x3e5f2a7b, 0x792e85df,
		0xeac3d972, 0xca9b7fe5, 0xbdcf5473, 0x895ad732, 0xc9d6b324, 0xd3549a72, 0xde72ab89, 0xf4a6dc53,
		0x6a8e752b, 0xa736d25f, 0xc3ad8296, 0xb435f689, 0x7fce594b, 0x529ca743, 0x3c4ab2d7, 0x94c8adf6,
		0x893746c2, 0x6ceda579, 0xcad36b75, 0x6f4a973e, 0xf3a49c56, 0xb645f2d9, 0xd72a56f8, 0x4b3d6fa9,
		0xd354cf2a, 0x26b4f5d8, 0x3e9f64ad, 0xae4fd326, 0x3f9247d6, 0xe4c67f95, 0xfed8c9b4, 0x249637db,
		0xdefabc54, 0xa9ebd87c, 0xcf2864ea, 0xf632d475, 0x5e3b6897, 0xed7f94b8, 0x67a4cfd2, 0x97a82e65,
		0x2369b7a4, 0x2ca3e6d4, 0xc57fba36, 0xdf3e7846, 0xde324ba5, 0x7ec56f24, 0xb598c3af, 0x389fd4ae,
		0xa3b6472c, 0x2f94a8be, 0x93fcab42, 0x82f34aeb, 0x94e8b372, 0x87c42b9e, 0x2f9b574c, 0x7ec693fa,
		0x9245fc67, 0x823bf4ce, 0x9357f84d, 0xed529a87, 0xb4625ead, 0xbcd4f6a9, 0x7863ca52, 0xd4762cef,
		0xe8d6c479, 0xbc46f579, 0xa9486fdc, 0xced6f289, 0xd8a3b629, 0x49fce523, 0x62e8db97, 0xc23bf769,
		0xa9c64d7f, 0x52dab6f7, 0x965cdf8e, 0xc4872fe9, 0x9764de53, 0x24bef897, 0x5b7a962c, 0x3f8d72be,
		0xd26fa89c, 0x58bf742e, 0xac3bd967, 0x36cae942, 0x48d3fb9c, 0xa2f59ed3, 0xa6f8379d, 0x29bf46d7,
		0x8cdbe243, 0x375c4bf9, 0x872f9dc5, 0x87a46ef5, 0x53d48ac9, 0x97e6ca3d, 0x2fec5a3b, 0x597dafe3,
		0x382ed7a9, 0xbc34d687, 0x869ecbf7, 0x7b38549a, 0x9f28746c, 0x95cb7e83, 0xec85f9a7, 0x2a947c8e,
		0x7ba689fd, 0xebc24893, 0xa362cf7e, 0xa48e3cb5, 0xe247589d, 0x7c92edaf, 0x84635c2d, 0xad2c6bfe,
		0xec456daf, 0x2d6e5f47, 0xfa9ce625, 0x7c4a8b62, 0x9cd728f5, 0x3be4a29d, 0xd62a589c, 0x843cb629,
		0x4ce5b6d3, 0x2fd6a9ce, 0x8d7af3bc, 0x8f37a695, 0xfe935da4, 0x4d8b6ea2, 0xa52dc4e9, 0x8e2a537b,
		0x7e23456f, 0x6cb8dafe, 0x957bf34d, 0x4ec72ad8, 0xa75c4982, 0x83afb76e, 0xb895fca6, 0x865abd24,
		0x9ae2475d, 0xf3c45eb8, 0xba4d2ef5, 0xb2da463e, 0xfd392a5e, 0x76a9fd58, 0x3ead48f6, 0x8ea62537,
		0xd6c35ba2, 0x758d9e24, 0xd524ec93, 0x67bc42a5, 0x354d9f87, 0xe2d3578f, 0xe87452fa, 0x5e439fca,
		0xd29b37c8, 0x8fe64c3b, 0x4ac5368d, 0x5e8acf9b, 0x6f9c3ad2, 0xaef3827b, 0x5328e46b, 0xbdef7ca9,
		0x3da592c4, 0x45fe7db2, 0xc9b65a3d, 0x4a578ec3, 0xc46deab9, 0xb3689edc, 0x84aed59f, 0x235b9af7,
		0xa9b6d48f, 0x6de379bf, 0x2749fa5e, 0x2469a7ef, 0xdf9e62a7, 0xb39a86d2, 0x8539b72c, 0x8dfa9ebc,
		0xdec397f5, 0xdba3c4e2, 0x9a38e6fd, 0xe98a734f, 0xe94b8d7f, 0x874cd9b3, 0xb75c6ef4, 0x9f56378c,
		0xc43f2d78, 0x74ea9253, 0x2c5dbef4, 0xbc7e26f9, 0x943b2c6d, 0x25faeb76, 0x53b278de, 0x6eb5948f,
		0xc4967358, 0x49f63a7e, 0x7a596ec4, 0x948cabf5, 0x945c638e, 0x6fd258b7, 0x697e8b3f, 0x56ab7823,
		0xc53b6a89, 0xa3bfc579, 0xaec45d36, 0xcdea9b28, 0x9e8f2356, 0xdb694a2e, 0xdf732e8a, 0xec7463d5,
		0xbf5ec9a8, 0x6dbfa984, 0xc4798e5a, 0x67e9382b, 0xe7ac3249, 0x5e238b9a, 0xbd632eaf, 0xaf92b685,
		0x6bcae435, 0x97236fd8, 0x37fcbea4, 0x5fe9da23, 0xb593a4f7, 0x3e27d84c, 0xa5db932f, 0x8c6274de,
		0xca54bd72, 0x63f42ed5, 0x6ad37285, 0xbd4fe7c9, 0x5f49a6b3, 0x38b592ec, 0x273d456b, 0x4e9253b7,
		0xf2da9b8c, 0xb85c642d, 0x3d7489ca, 0x7426fe3b, 0x4bce6ad2, 0x3276becd, 0x96f43bec, 0xf296dba4,
		0x3ebc8d72, 0xf593b4ca, 0x2a63547f, 0xa5bcd87e, 0x39fd25ae, 0xce6f4b38, 0xf36cd978, 0x62e94a37,
	}
)

// TsSeconds2Hash generate hash from seconds ts.
func TsSeconds2Hash(tsSecond int64) string {
	hashSeedMills := time.Now().UnixNano() / time.Millisecond.Nanoseconds()
	randomIndex := rand.Intn(255)
	hashVal := md5Hex(strconv.FormatInt(hashSeedMills, 10))
	hashVal = hashVal[:16]
	ris := fmt.Sprintf("%02x", randomIndex)
	hashVal = replaceStr(hashVal, ris, 0)
	val := table[randomIndex]
	ts := fmt.Sprintf("%08x", tsSecond)
	poses := decompress(val)
	for i, pos := range poses {
		s := ts[i : i+1]
		hashVal = replaceStr(hashVal, s, int(pos))
	}
	return hashVal
}

func replaceStr(origin, s string, pos int) string {
	if pos > 0 {
		return origin[:pos] + s + origin[pos+len(s):]
	}
	return s + origin[pos+len(s):]
}

func decompress(mixed uint64) []uint64 {
	filterVal := uint64((1 << _bits) - 1)
	val := make([]uint64, _splitOn)
	itemNums := _splitOn
	mixedArr := []uint64{mixed}
	n := uint64(0)
	for _, sval := range mixedArr {
		for k := uint64(0); k < _splitOn; k++ {
			var dval uint64
			if k == 0 {
				dval = sval & filterVal
			} else {
				dval = (sval >> (_bits * k)) & filterVal
			}
			val[k] = dval
			n++
			if n == itemNums {
				break
			}
		}
		if n == itemNums {
			break
		}
	}
	return val
}

// Hash2TsSeconds parse ts seconds from hash.
func Hash2TsSeconds(timeHash string) (ts int64, err error) {
	randomIndex, err := strconv.ParseInt(timeHash[0:2], 16, 64)
	if err != nil {
		return
	}
	val := table[randomIndex]
	poses := decompress(val)
	tsStr := ""
	for _, pos := range poses {
		tsStr = tsStr + timeHash[pos:pos+1]
	}
	ts, err = strconv.ParseInt(tsStr, 16, 64)
	return
}
