package gnet

import (
	"encoding/binary"
	"fmt"
	"math"
)

var (
	bitMasksBig    = []byte{0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}
	bitMasksLittle = []byte{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}
)

type BitSplit struct {
	p    []int
	size int
}

func (b BitSplit) Size() int {
	return b.size
}

func (b BitSplit) All() []int {
	a := make([]int, len(b.p))
	for i := 0; i < len(b.p); i++ {
		a[i] = b.p[i]
	}
	return a
}

func (b BitSplit) RangeIs(v int, handle func(idx int)) {
	for i := 0; i < len(b.p); i++ {
		if b.p[i] == v {
			handle(i)
		}
	}
}

func (b BitSplit) Is0(i int) bool {
	if i >= b.size {
		return false
	}
	return b.p[i] == 0
}

func (b BitSplit) Is1(i int) bool {
	if i >= b.size {
		return false
	}
	return b.p[i] == 1
}

func (b BitSplit) String() string {
	return fmt.Sprintf("%v", b.p)
}

func binarySplit(p []byte, bitMasks []byte, reverse bool) BitSplit {
	bs := BitSplit{}
	bs.p = make([]int, 0, len(p)*8) // *8 是因为每个字节占 8 位
	for _, b := range p {
		for _, bm := range bitMasks {
			v := 0
			if b&bm > 0 {
				v = 1
			}
			if reverse {
				bs.p = append([]int{v}, bs.p...)
			} else {
				bs.p = append(bs.p, v)
			}
		}
	}
	bs.size = len(bs.p)
	return bs
}

func bytesSplit(groupSize int, p []byte) [][]byte {
	dividend := len(p)
	divisor := groupSize

	size := (dividend / divisor) + (dividend % divisor)

	waitSplit := make([][]byte, size)
	batchSize := groupSize
	for i := 0; i < len(p); i += batchSize {
		end := i + batchSize
		if end > len(p) {
			break // 丢弃多余的元素
		}
		waitSplit[i/batchSize] = p[i:end]
	}
	return waitSplit
}

type bigEndian struct{}

func (bigEndian) String() string { return "BigEndian" }

func (bigEndian) GoString() string { return "gnet.BigEndian" }

func (bigEndian) PutUint16(b []byte, v uint16) {
	binary.BigEndian.PutUint16(b, v)
}

func (bigEndian) PutUint32(b []byte, v uint32) {
	binary.BigEndian.PutUint32(b, v)
}

func (bigEndian) PutUint64(b []byte, v uint64) {
	binary.BigEndian.PutUint64(b, v)
}

func (b bigEndian) BitSplit(p []byte) BitSplit {
	if len(p) == 1 {
		return b.BitSplitWith(1, p)
	}
	return b.BitSplitWith(2, p)
}

func (bigEndian) BitSplitWith(groupSize int, p []byte) BitSplit {
	allBits := make([]int, 0, len(p)*8)
	for _, bits := range bytesSplit(groupSize, p) {
		spit := binarySplit(bits, bitMasksLittle, false).All()
		allBits = append(allBits, spit...)
	}
	return BitSplit{p: allBits, size: len(allBits)}
}

func (b bigEndian) BigMerge(p [8]byte) uint8 {
	for _, n := range p {
		if n != 0 && n != 1 {
			panic("number must be 0 or 1")
		}
	}
	var result uint8
	for i := len(p) - 1; i >= 0; i-- {
		result |= p[i] << (7 - i)
	}
	return result
}

func (b bigEndian) Int16(p []byte) int16 {
	return int16(NegativeCovert(int64(b.Uint16(p))))
}

func (b bigEndian) Int32(p []byte) int32 {
	return int32(NegativeCovert(int64(b.Uint32(p))))
}

func (b bigEndian) Int64(p []byte) int64 {
	return NegativeCovert(int64(b.Uint32(p)))
}

func (b bigEndian) Uint16(p []byte) uint16 {
	if len(p) != 2 {
		return 0
	}
	return binary.BigEndian.Uint16(p)
}

func (b bigEndian) Uint32(p []byte) uint32 {
	if len(p) != 4 {
		return 0
	}
	return binary.BigEndian.Uint32(p)
}

func (b bigEndian) Uint64(p []byte) uint64 {
	switch len(p) {
	case 1:
		return uint64(p[0])
	case 2:
		return uint64(b.Uint16(p[:2]))
	case 4:
		return uint64(b.Uint32(p[:4]))
	case 8:
		return binary.BigEndian.Uint64(p)
	default:
		return 0
	}
}

func (b bigEndian) Float32(p []byte) float32 {
	if len(p) != 4 {
		return 0
	}
	return math.Float32frombits(b.Uint32(p))
}

func (b bigEndian) Float64(p []byte) float64 {
	if len(p) != 8 {
		return 0
	}
	return math.Float64frombits(b.Uint64(p))
}

func (b bigEndian) SliceToInt(slice []uint16) int {
	result := 0
	for _, v := range slice {
		result = result<<16 | int(v)
	}
	return result
}

func (b bigEndian) IntToSlice(num int, length int) []uint16 {
	slice := make([]uint16, length)
	for i := length - 1; i >= 0; i-- {
		slice[i] = uint16(num & 0xFFFF)
		num >>= 16
	}
	return slice
}

type littleEndian struct{}

func (littleEndian) String() string { return "LittleEndian" }

func (littleEndian) GoString() string { return "gnet.LittleEndian" }

func (littleEndian) PutUint16(b []byte, v uint16) {
	binary.LittleEndian.PutUint16(b, v)
}

func (littleEndian) PutUint32(b []byte, v uint32) {
	binary.LittleEndian.PutUint32(b, v)
}

func (littleEndian) PutUint64(b []byte, v uint64) {
	binary.LittleEndian.PutUint64(b, v)
}

func (l littleEndian) BitSplit(p []byte) BitSplit {
	if len(p) == 1 {
		return l.BitSplitWith(1, p)
	}
	return l.BitSplitWith(2, p)
}

func (littleEndian) BitSplitWith(groupSize int, p []byte) BitSplit {
	allBits := make([]int, 0, len(p)*8)
	for _, bits := range bytesSplit(groupSize, p) {
		spit := binarySplit(bits, bitMasksLittle, true).All()
		allBits = append(allBits, spit...)
	}
	return BitSplit{p: allBits, size: len(allBits)}
}

func (littleEndian) BitMerge(p [8]byte) uint8 {
	for _, n := range p {
		if n != 0 && n != 1 {
			panic("number must be 0 or 1")
		}
	}
	var result uint8
	for i := 0; i < len(p); i++ {
		result |= p[i] << i
	}
	return result
}

// Int16 Range: -32768 through 32767.
func (l littleEndian) Int16(p []byte) int16 {
	return int16(NegativeCovert(int64(l.Uint16(p))))
}

func (l littleEndian) Int32(p []byte) int32 {
	return int32(NegativeCovert(int64(l.Uint32(p))))
}

func (l littleEndian) Int64(p []byte) int64 {
	return NegativeCovert(int64(l.Uint32(p)))
}

func (littleEndian) Uint16(p []byte) uint16 {
	if len(p) != 2 {
		return 0
	}
	return binary.LittleEndian.Uint16(p)
}

func (littleEndian) Uint32(p []byte) uint32 {
	if len(p) != 4 {
		return 0
	}
	return binary.LittleEndian.Uint32(p)
}

func (littleEndian) Uint64(b []byte) uint64 {
	if len(b) != 8 {
		return 0
	}
	return binary.LittleEndian.Uint64(b)
}

func (l littleEndian) Float32(p []byte) float32 {
	if len(p) != 4 {
		return 0
	}
	return math.Float32frombits(l.Uint32(p))
}

func (l littleEndian) Float64(p []byte) float64 {
	if len(p) != 8 {
		return 0
	}
	return math.Float64frombits(l.Uint64(p))
}

func NegativeCovert(i int64) int64 {
	if i < 0 {
		i = -i
		i = ^i + 1
	}
	return i
}

// SetBit 将指定的 bit 设置为 1
func SetBit(reg *uint16, bitPos uint) {
	*reg |= 1 << bitPos // 使用 OR 操作将
}

// ClearBit 清除寄存器中指定位置的 bit. 操作将指定的 bit 清除为 0
func ClearBit(reg *uint16, bitPos uint) {
	*reg &^= 1 << bitPos // 使用 AND NOT 操作将指定的 bit 清除为 0
}

// ToggleBit 切换寄存器中指定位置的 bit, 0 变 1. 1 变 0
func ToggleBit(reg *uint16, bitPos uint) {
	*reg ^= 1 << bitPos // 使用 XOR 操作切换指定的 bit
}

// SplitNumber 分割数字, 将 num 分割成单个最大不超过 max 的一组数据
func SplitNumber(num, max int) []int {
	if num <= max {
		return []int{num}
	}
	var result []int
	for num > max {
		result = append(result, max)
		num -= max
	}
	if num > 0 {
		result = append(result, num)
	}
	return result
}

// 举例:
// 数值 0x22 0x11 使用两个字节储存: 高位字节是 0x22, 低位字节是 0x11
// BigEndian 高位字节在前, 低位字节在后. 即 0x2211
// LittleEndian 低位字节在前, 高位字节在后. 即 0x1122
// 只有读取的时候才必须区分字节序, 其他情况都不用考虑
// BigEndian 与 LittleEndian 已实现 binary.ByteOrder
var (
	BigEndian    bigEndian
	LittleEndian littleEndian
)

type BitSplitter interface {
	BitSplit(p []byte) BitSplit
}
