package dsp

import "math"

// nextPow2 returns the smallest power of two >= n (and at least 1).
func nextPow2(n int) int {
	p := 1
	for p < n {
		p <<= 1
	}
	return p
}

// fftRadix2 computes the in-place iterative radix-2 Cooley-Tukey FFT of the
// complex signal held in re/im. len(re) == len(im) must be a power of two. The
// transform overwrites re/im with the frequency-domain result. This is a small
// self-contained implementation (no external dependency) used by the synthetic
// fft op.
func fftRadix2(re, im []float64) {
	n := len(re)
	if n <= 1 {
		return
	}

	// Bit-reversal permutation.
	for i, j := 1, 0; i < n; i++ {
		bit := n >> 1
		for ; j&bit != 0; bit >>= 1 {
			j ^= bit
		}
		j ^= bit
		if i < j {
			re[i], re[j] = re[j], re[i]
			im[i], im[j] = im[j], im[i]
		}
	}

	// Danielson-Lanczos butterflies.
	for length := 2; length <= n; length <<= 1 {
		ang := -2 * math.Pi / float64(length)
		wReal, wImag := math.Cos(ang), math.Sin(ang)
		for i := 0; i < n; i += length {
			curReal, curImag := 1.0, 0.0
			half := length >> 1
			for k := 0; k < half; k++ {
				a := i + k
				b := i + k + half
				tReal := curReal*re[b] - curImag*im[b]
				tImag := curReal*im[b] + curImag*re[b]
				re[b] = re[a] - tReal
				im[b] = im[a] - tImag
				re[a] += tReal
				im[a] += tImag
				curReal, curImag = curReal*wReal-curImag*wImag, curReal*wImag+curImag*wReal
			}
		}
	}
}
