package client

import (
	"encoding/binary"
	"log"

	"go-ts/pkg/protocol"

	"gopkg.in/hraban/opus.v2"
)

const (
	// TeamSpeak Codecs
	CodecOpusVoice = 4
	CodecOpusMusic = 5
)

func (c *Client) handleVoice(pkt *protocol.Packet) {
	// Only process Opus packets
	// Parse Voice Header (Server -> Client)
	// VId(2) + CId(2) + Codec(1) + Data

	var data []byte = pkt.Data

	// Decrypt if Encrypted
	if !pkt.Header.FlagUnencrypted() {
		if c.Handshake == nil || len(c.Handshake.SharedIV) == 0 {
			log.Println("Received encrypted voice packet but no SharedIV available. Dropping.")
			return
		}

		crypto := &protocol.CryptoState{
			SharedIV:     c.Handshake.SharedIV,
			SharedMac:    c.Handshake.SharedMac,
			GenerationID: 0,
		}
		// Server->Client = false
		key, nonce := crypto.GenerateKeyNonce(&pkt.Header, false)

		// Meta for Server->Client: PID(2) + PT(1) = 3 bytes
		meta := make([]byte, 3)
		binary.BigEndian.PutUint16(meta[0:2], pkt.Header.PacketID)
		meta[2] = pkt.Header.Type

		var err error
		data, err = protocol.DecryptEAX(key, nonce, meta, pkt.Data, pkt.Header.MAC[:])
		if err != nil {
			// Voice decryption failure is common if keys mismatch or packet loss affects counter?
			// But EAX doesn't depend on counter state, only PID which is in header.
			log.Printf("Voice decryption failed: %v", err)
			return
		}
	}

	if len(data) < 6 {
		// Ignore empty/too small packets (e.g. silence or end)
		return
	}

	// The first 2 bytes are the sequence ID, not the client ID for the decoder key.
	// The client ID is at data[2:4]
	// vid := binary.BigEndian.Uint16(data[0:2]) // Sequence ID
	vid := binary.BigEndian.Uint16(data[2:4]) // Talking Client ID (CORRECT KEY)
	codec := data[4]
	voiceData := data[5:]

	// Only process Opus packets
	if codec != CodecOpusVoice && codec != CodecOpusMusic {
		log.Printf("Received non-Opus voice packet (Codec=%d). Ignoring echo.", codec)
		return
	}

	channels := 1
	if codec == CodecOpusMusic {
		channels = 2
	}

	// 1. Get or Create Decoder for this VID
	decoder, ok := c.VoiceDecoders[vid]
	if !ok {
		var err error
		decoder, err = opus.NewDecoder(48000, channels)
		if err != nil {
			log.Printf("Failed to create Opus decoder: %v", err)
			return
		}
		c.VoiceDecoders[vid] = decoder
	}

	// 2. Decode Opus to PCM
	// Max frame size for 120ms at 48kHz is 5760 samples
	pcm := make([]int16, 5760*channels)
	n, err := decoder.Decode(voiceData, pcm)
	if err != nil {
		log.Printf("Opus decode error: %v", err)
		return
	}
	pcm = pcm[:n*channels]

	if n != 960 {
		log.Printf("WARNING: Unusual Opus frame size: %d samples (expected 960 for 20ms)", n)
	}

	// 3. Process PCM: Reduce Volume (divide by 4)
	for i := range pcm {
		pcm[i] = pcm[i] / 10
	}

	// 4. Get or Create Encoder
	if c.VoiceEncoder == nil {
		var err error
		app := opus.AppVoIP
		if channels == 2 {
			app = opus.AppAudio
		}
		encoder, err := opus.NewEncoder(48000, channels, app)
		if err != nil {
			log.Printf("Failed to create Opus encoder: %v", err)
			return
		}

		// Optimize Quality
		encoder.SetBitrate(64000) // 64 kbps (High Quality for Voice)
		encoder.SetComplexity(10) // Max Complexity (Best Quality)

		c.VoiceEncoder = encoder
	}

	// 5. Encode PCM to Opus
	encoded := make([]byte, 1024)
	nEnc, err := c.VoiceEncoder.Encode(pcm, encoded)
	if err != nil {
		log.Printf("Opus encode error: %v", err)
		return
	}
	encoded = encoded[:nEnc]

	// log.Printf("Voice Processed (CGO): VID=%d, In=%d bytes, PCM=%d samples, Out=%d bytes", vid, len(voiceData), n, nEnc)

	// 6. Build echo packet (Client -> Server)
	// Payload format: [VId(2)] [Codec(1)] [Data...]
	echoData := make([]byte, 2+1+len(encoded))

	c.VoicePacketID++ // Increment counter before using it

	// Correctly set VId in Payload to be the Sequence Number (not ClientID)
	binary.BigEndian.PutUint16(echoData[0:2], c.VoicePacketID)
	echoData[2] = codec
	copy(echoData[3:], encoded)

	echoPkt := protocol.NewPacket(protocol.PacketTypeVoice, echoData)
	echoPkt.Header.PacketID = c.VoicePacketID
	echoPkt.Header.ClientID = c.ClientID

	// Encrypt voice packet
	if c.Handshake != nil && len(c.Handshake.SharedIV) > 0 {
		crypto := &protocol.CryptoState{
			SharedIV:     c.Handshake.SharedIV,
			SharedMac:    c.Handshake.SharedMac,
			GenerationID: 0,
		}
		key, nonce := crypto.GenerateKeyNonce(&echoPkt.Header, true)

		meta := make([]byte, 5)
		binary.BigEndian.PutUint16(meta[0:2], echoPkt.Header.PacketID)
		binary.BigEndian.PutUint16(meta[2:4], echoPkt.Header.ClientID)
		meta[4] = echoPkt.Header.Type

		encData, mac, err := protocol.EncryptEAX(key, nonce, meta, echoPkt.Data)
		if err != nil {
			log.Printf("Voice encryption failed: %v", err)
			return
		}
		echoPkt.Data = encData
		copy(echoPkt.Header.MAC[:], mac)
	} else {
		if c.Handshake != nil && len(c.Handshake.SharedMac) > 0 {
			copy(echoPkt.Header.MAC[:], c.Handshake.SharedMac)
		} else {
			echoPkt.Header.MAC = protocol.HandshakeMac
		}
	}

	c.Conn.SendPacket(echoPkt)
}
