package utils

import (
	"bufio"
	"encoding/binary"
	"fmt"
	"os"
)

// WriteWAVFile writes audio samples to a WAV file.
// Samples should be in the range -1.0 to 1.0.
// Output is mono 16-bit PCM.
func WriteWAVFile(filepath string, samples []float64, sampleRate int) error {
	if len(samples) == 0 {
		return fmt.Errorf("no samples to write")
	}

	file, err := os.Create(filepath)
	if err != nil {
		return fmt.Errorf("failed to create file: %w", err)
	}
	w := bufio.NewWriterSize(file, 64*1024)

	// Write WAV and flush; check close to ensure data is persisted.
	err = func() error {

		// WAV parameters
		channels := 1
		bitsPerSample := 16
		bytesPerSample := bitsPerSample / 8
		byteRate := sampleRate * channels * bytesPerSample
		blockAlign := channels * bytesPerSample
		dataSize := len(samples) * bytesPerSample
		totalSize := 36 + dataSize // 36 = header size before data chunk

		// Write 44-byte WAV header in one go
		header := make([]byte, 44)
		copy(header[0:4], "RIFF")
		binary.LittleEndian.PutUint32(header[4:8], uint32(totalSize))
		copy(header[8:12], "WAVE")
		copy(header[12:16], "fmt ")
		binary.LittleEndian.PutUint32(header[16:20], 16) // chunk size
		binary.LittleEndian.PutUint16(header[20:22], 1)  // PCM format
		binary.LittleEndian.PutUint16(header[22:24], uint16(channels))
		binary.LittleEndian.PutUint32(header[24:28], uint32(sampleRate))
		binary.LittleEndian.PutUint32(header[28:32], uint32(byteRate))
		binary.LittleEndian.PutUint16(header[32:34], uint16(blockAlign))
		binary.LittleEndian.PutUint16(header[34:36], uint16(bitsPerSample))
		copy(header[36:40], "data")
		binary.LittleEndian.PutUint32(header[40:44], uint32(dataSize))

		if _, err := w.Write(header); err != nil {
			return err
		}

		// Convert all float64 samples to 16-bit PCM in a single buffer
		buf := Float64ToPCM16(samples)

		if _, err := w.Write(buf); err != nil {
			return err
		}

		return w.Flush()
	}()
	if err2 := file.Close(); err2 != nil {
		if err == nil {
			err = fmt.Errorf("failed to close file: %w", err2)
		}
	}
	return err
}