package aoiprxkit

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

const (
	DefaultSAPGroup = "224.2.127.254"
	DefaultSAPPort  = 9875
)

type SAPPacket struct {
	Version         uint8
	AddressTypeIPv6 bool
	IsDelete        bool
	Encrypted       bool
	Compressed      bool
	AuthLenWords    uint8
	MessageIDHash   uint16
	OriginSource    net.IP
	PayloadType     string
	Payload         []byte
}

type SAPAnnouncement struct {
	ReceivedAt  string  `json:"receivedAt"`
	SourceAddr  string  `json:"sourceAddr"`
	MessageID   uint16  `json:"messageIdHash"`
	Delete      bool    `json:"delete"`
	PayloadType string  `json:"payloadType"`
	SDP         string  `json:"sdp"`
	ParsedSDP   SDPInfo `json:"parsedSdp"`
}

func ParseSAPPacket(buf []byte) (SAPPacket, error) {
	if len(buf) < 8 {
		return SAPPacket{}, fmt.Errorf("SAP packet too short")
	}

	b0 := buf[0]
	version := b0 >> 5
	if version != 1 {
		return SAPPacket{}, fmt.Errorf("unsupported SAP version %d", version)
	}

	addrTypeIPv6 := (b0 & 0x10) != 0
	isDelete := (b0 & 0x04) != 0
	encrypted := (b0 & 0x02) != 0
	compressed := (b0 & 0x01) != 0
	authLenWords := buf[1]
	msgID := binary.BigEndian.Uint16(buf[2:4])

	hdrLen := 4
	var origin net.IP
	if addrTypeIPv6 {
		if len(buf) < hdrLen+16 {
			return SAPPacket{}, fmt.Errorf("SAP packet too short for IPv6 source")
		}
		origin = net.IP(buf[hdrLen : hdrLen+16])
		hdrLen += 16
	} else {
		if len(buf) < hdrLen+4 {
			return SAPPacket{}, fmt.Errorf("SAP packet too short for IPv4 source")
		}
		origin = net.IP(buf[hdrLen : hdrLen+4])
		hdrLen += 4
	}

	authBytes := int(authLenWords) * 4
	if len(buf) < hdrLen+authBytes {
		return SAPPacket{}, fmt.Errorf("SAP packet too short for auth section")
	}
	hdrLen += authBytes

	if encrypted || compressed {
		return SAPPacket{}, fmt.Errorf("encrypted/compressed SAP payloads are not supported")
	}

	payloadType := "application/sdp"
	payloadStart := hdrLen

	if len(buf) > payloadStart && !(len(buf)-payloadStart >= 4 && string(buf[payloadStart:payloadStart+4]) == "v=0\n" || len(buf)-payloadStart >= 5 && string(buf[payloadStart:payloadStart+5]) == "v=0\r\n") {
		nul := -1
		for i := payloadStart; i < len(buf); i++ {
			if buf[i] == 0 {
				nul = i
				break
			}
		}
		if nul == -1 {
			return SAPPacket{}, fmt.Errorf("SAP payload type missing NUL terminator")
		}
		payloadType = string(buf[payloadStart:nul])
		payloadStart = nul + 1
	}

	if payloadStart > len(buf) {
		return SAPPacket{}, fmt.Errorf("invalid SAP payload start")
	}

	return SAPPacket{
		Version:         version,
		AddressTypeIPv6: addrTypeIPv6,
		IsDelete:        isDelete,
		Encrypted:       encrypted,
		Compressed:      compressed,
		AuthLenWords:    authLenWords,
		MessageIDHash:   msgID,
		OriginSource:    origin,
		PayloadType:     payloadType,
		Payload:         append([]byte(nil), buf[payloadStart:]...),
	}, nil
}
