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    []uint8
	size uint64
}

func (b *BitSplit) Size() uint64 {
	return b.size
}

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

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

func (b *BitSplit) Is1(i uint64) 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 := new(BitSplit)
	bs.p = make([]uint8, 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([]byte{uint8(v)}, bs.p...)
			} else {
				bs.p = append(bs.p, uint8(v))
			}
		}
	}
	bs.size = uint64(len(bs.p))
	return bs
}

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 {
	return binarySplit(p, bitMasksBig, false)
}

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 {
	if len(p) != 8 {
		return 0
	}
	return binary.BigEndian.Uint64(p)
}

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))
}

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 (littleEndian) BitSplit(p []byte) *BitSplit {
	return binarySplit(p, bitMasksLittle, true)
}

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
}

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

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

type BinaryOrder interface {
	PutUint16(b []byte, v uint16)
	PutUint32(b []byte, v uint32)
	PutUint64(b []byte, v uint64)
	Int16(p []byte) int16
	Int32(p []byte) int32
	Int64(p []byte) int64
	Uint16(p []byte) uint16
	Uint32(p []byte) uint32
	Uint64(p []byte) uint64
	Float32(p []byte) float32
	Float64(p []byte) float64
	BitSplitter
}
