// cmd/wmtest — Ferrite watermark self-test tool.
//
// Generates a mono WAV file containing only the spread-spectrum watermark
// signal (silence + watermark, scaled up for visibility). Run wmdecode on
// the output to verify embedder and decoder work without FM transmission.
//
// Usage:
//
//	wmtest --key <license-key> --output test.wav --duration 30s
//	wmdecode test.wav <license-key>
package main

import (
	"encoding/binary"
	"flag"
	"fmt"
	"math"
	"os"
	"time"

	"github.com/jan/fm-rds-tx/internal/watermark"
)

func main() {
	key      := flag.String("key",      "free",       "License key to embed")
	output   := flag.String("output",   "wmtest.wav", "Output WAV file")
	duration := flag.Duration("duration", 60*time.Second, "Duration (min 45s for 2 full frames)")
	flag.Parse()

	const compRate = watermark.CompositeRate // 228000
	const recRate  = watermark.RecordingRate // 48000

	nSamples := int(duration.Seconds() * float64(recRate))

	chipRate := watermark.ChipRate
	frameSeconds := float64(128 * watermark.PnChips) / float64(chipRate)
	nFrames := duration.Seconds() / frameSeconds

	fmt.Printf("Ferrite watermark self-test\n")
	fmt.Printf("  Key:       %s\n", *key)
	fmt.Printf("  ChipRate:  %d Hz (PN bandwidth 0–%d Hz)\n", chipRate, chipRate/2)
	fmt.Printf("  Frame:     %.1fs (%d chips × 128 bits @ %d Hz)\n", frameSeconds, watermark.PnChips, chipRate)
	fmt.Printf("  Duration:  %s (%d samples @ %dHz, %.1f frames)\n\n", *duration, nSamples, recRate, nFrames)

	embedder := watermark.NewEmbedder(*key)
	samples  := make([]float64, 0, nSamples)

	// Drive embedder at composite rate, collect samples at recording rate.
	// Bresenham: accumulate recRate each composite step; when >= compRate,
	// emit one recording sample and subtract compRate.
	accum := 0
	var last float64
	for len(samples) < nSamples {
		last   = embedder.NextSample()
		accum += recRate
		if accum >= compRate {
			accum -= compRate
			samples = append(samples, last)
		}
	}

	// RMS
	var rmsAcc float64
	for _, s := range samples {
		rmsAcc += s * s
	}
	rms := math.Sqrt(rmsAcc / float64(len(samples)))
	fmt.Printf("Watermark RMS: %.1f dBFS (nominal -48 dBFS)\n", 20*math.Log10(rms+1e-12))

	if err := writeMonoWAV(*output, samples, recRate); err != nil {
		fmt.Fprintf(os.Stderr, "write WAV: %v\n", err)
		os.Exit(1)
	}
	fmt.Printf("Written: %s\n\n", *output)
	fmt.Printf("Decode with:\n")
	fmt.Printf("  .\\wmdecode.exe %s %q\n\n", *output, *key)
	fmt.Printf("Expected: RS decode clean + MATCH\n")
}

func writeMonoWAV(path string, samples []float64, rate int) error {
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	defer f.Close()

	le      := binary.LittleEndian
	dataSz  := uint32(len(samples) * 2)

	f.Write([]byte("RIFF"))
	binary.Write(f, le, 36+dataSz)
	f.Write([]byte("WAVE"))
	f.Write([]byte("fmt "))
	binary.Write(f, le, uint32(16))
	binary.Write(f, le, uint16(1))        // PCM
	binary.Write(f, le, uint16(1))        // mono
	binary.Write(f, le, uint32(rate))
	binary.Write(f, le, uint32(rate*2))   // byte rate
	binary.Write(f, le, uint16(2))        // block align
	binary.Write(f, le, uint16(16))       // bits/sample
	f.Write([]byte("data"))
	binary.Write(f, le, dataSz)
	for _, s := range samples {
		// Scale to int16 range — watermark at -48dBFS → ~0.004 amplitude
		// Multiply by 32767 to get full 16-bit range
		v := s * 32767.0
		if v >  32767 { v =  32767 }
		if v < -32768 { v = -32768 }
		binary.Write(f, le, int16(v))
	}
	return nil
}
