package audio

import "fmt"

// Codec converts between the wire payload of a network audio stream (Icom 50003)
// and OpsLog's internal PCM (16 kHz mono 16-bit little-endian — the format the
// capture/render engine and the pcmRing use). It exists so the transport code
// (icomaudio.go) never hard-codes a format: today PCM is an identity passthrough;
// tomorrow an Opus codec implements the same two methods and drops in unchanged.
// This mirrors how civTransport abstracts the CAT byte stream from its transport.
type Codec interface {
	// Name is a short label for logs/UI.
	Name() string
	// Decode turns one received audio payload into internal PCM. The returned
	// slice is freshly allocated (the caller may retain it).
	Decode(payload []byte) ([]byte, error)
	// Encode turns internal PCM into a payload to transmit.
	Encode(pcm []byte) ([]byte, error)
}

// pcm16Codec is the uncompressed 16-bit-PCM codec — the Icom "uncompressed"
// audio mode (rxcodec/txcodec in the conninfo). Icom sends little-endian 16-bit
// mono samples, which is byte-for-byte OpsLog's internal format, so decode/encode
// are copies. It is the Phase-4/5 default: zero-dependency, lossless, ideal on a
// LAN. Opus (for WAN/internet bandwidth) becomes another Codec later.
//
// NOTE: rate conversion is deliberately NOT this layer's job. The Icom RX audio
// is 16 kHz = our internal rate, so RX needs none. The rig's TX side may run at a
// different rate (the captured conninfo showed 8 kHz) — Phase 5 will resample in
// the TX path before Encode; keeping the codec rate-agnostic keeps that concern
// in one place.
type pcm16Codec struct{}

// NewPCM16Codec returns the uncompressed 16-bit PCM codec.
func NewPCM16Codec() Codec { return pcm16Codec{} }

func (pcm16Codec) Name() string { return "pcm16" }

func (pcm16Codec) Decode(payload []byte) ([]byte, error) {
	// Icom PCM payloads are whole 16-bit samples; an odd length means a truncated
	// packet — trim the stray byte rather than emit a half-sample click.
	n := len(payload) &^ 1
	if n != len(payload) {
		if n == 0 {
			return nil, fmt.Errorf("pcm16: payload too short (%d bytes)", len(payload))
		}
	}
	out := make([]byte, n)
	copy(out, payload[:n])
	return out, nil
}

func (pcm16Codec) Encode(pcm []byte) ([]byte, error) {
	out := make([]byte, len(pcm))
	copy(out, pcm)
	return out, nil
}
