package cassandra

import (
	"bytes"
	"encoding/binary"
	"git.loafle.net/overflow/overflow_probe/matcher/packet"
	"git.loafle.net/overflow/overflow_probe/model/scaninfo"
)

const (
	COMPRESSION = "COMPRESSION"
	CQL_VERSION = "CQL_VERSION"
)

type cassandra struct {
	Version uint8
	Flags   uint8
	Stream  uint16
	Opcode  uint8
	Length  uint32
}

type CassandraMatcher struct {
	packets []*packet.Packet
}

func NewCassandraMatcher() *CassandraMatcher {

	cassMatcher := &CassandraMatcher{}
	c := cassandra{
		Version: 4,
		Flags:   0,
		Stream:  0,
		Opcode:  5,
		Length:  0,
	}
	writer := new(bytes.Buffer)
	binary.Write(writer, binary.LittleEndian, c)

	cassMatcher.packets = append(cassMatcher.packets, packet.NewPacket(writer.Bytes(), writer.Len()))

	return cassMatcher
}

func (t *CassandraMatcher) ServiceName() string {
	return "Cassandra"
}

func (t *CassandraMatcher) PacketCount() int {
	return len(t.packets)
}
func (t *CassandraMatcher) Packet(index int) *packet.Packet {
	return t.packets[index]
}

func (t *CassandraMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool {
	return false
}

func (t *CassandraMatcher) IsNoResponse(index int) bool {
	return false
}

func (t *CassandraMatcher) IsPrePacket() bool {
	return false
}

func (t *CassandraMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool {

	if packet == nil {
		return false
	}

	reader := new(bytes.Buffer)
	reader.Write(packet.Buffer)

	c := cassandra{}
	if err := binary.Read(reader, binary.BigEndian, &c); err != nil {
		return false
	}
	if c.Version != 0x84 {
		return false
	}
	if c.Flags != 0x00 {
		return false
	}
	if c.Stream != 0x00 {
		return false
	}
	if c.Opcode != 0x06 {
		return false
	}
	var itemcount uint16

	if binary.Read(reader, binary.BigEndian, &itemcount) != nil {
		return false
	}

	if itemcount != 0 && itemcount != 2 {
		return false
	}

	return true

}
