package dsp

import "math"

// FMModulator converts a composite baseband signal into FM-modulated IQ samples.
// The modulated output represents the instantaneous frequency deviation around
// a zero-IF carrier (baseband IQ). For a real SDR transmitter the SDR hardware
// then upconverts this to the desired center frequency.
type FMModulator struct {
	// MaxDeviation is the peak frequency deviation in Hz (±75 kHz for FM broadcast).
	MaxDeviation float64
	SampleRate   float64

	phase float64 // accumulated carrier phase in radians
}

// NewFMModulator creates a modulator with broadcast FM defaults.
func NewFMModulator(sampleRate float64) *FMModulator {
	return &FMModulator{
		MaxDeviation: 75000, // ±75 kHz
		SampleRate:   sampleRate,
	}
}

// Modulate converts a single composite sample (normalized to [-1,+1] representing
// full deviation) into an IQ pair.
func (m *FMModulator) Modulate(composite float64) (i, q float64) {
	// Instantaneous frequency offset = composite * maxDeviation
	// Phase increment per sample = 2π * freq_offset / sampleRate
	freqOffset := composite * m.MaxDeviation
	m.phase += 2 * math.Pi * freqOffset / m.SampleRate

	// Keep phase bounded to avoid float64 precision loss over long runs
	if m.phase > math.Pi || m.phase < -math.Pi {
		m.phase -= 2 * math.Pi * math.Floor((m.phase+math.Pi)/(2*math.Pi))
	}

	i = math.Cos(m.phase)
	q = math.Sin(m.phase)
	return i, q
}

// Reset clears the modulator phase.
func (m *FMModulator) Reset() {
	m.phase = 0
}
