package oggvorbis

import (
	"context"
	"fmt"
	"io"

	"github.com/jan/fm-rds-tx/internal/ingest"
	"github.com/jan/fm-rds-tx/internal/ingest/decoder"
	libvorbis "github.com/jfreymuth/oggvorbis"
)

type Decoder struct{}

func New() *Decoder { return &Decoder{} }

func (d *Decoder) Name() string { return "oggvorbis-native" }

func (d *Decoder) DecodeStream(ctx context.Context, r io.Reader, meta decoder.StreamMeta, emit func(ingest.PCMChunk) error) error {
	if r == nil {
		return fmt.Errorf("%w: ogg/vorbis decoder stream reader is nil", decoder.ErrUnsupported)
	}
	if emit == nil {
		return fmt.Errorf("%w: ogg/vorbis decoder emit callback is nil", decoder.ErrUnsupported)
	}

	dec, err := libvorbis.NewReader(r)
	if err != nil {
		return fmt.Errorf("%w: ogg/vorbis decoder init: %v", decoder.ErrUnsupported, err)
	}

	channels := dec.Channels()
	if channels <= 0 {
		if meta.Channels > 0 {
			channels = meta.Channels
		} else {
			return fmt.Errorf("%w: ogg/vorbis decoder invalid channel count", decoder.ErrUnsupported)
		}
	}

	sampleRate := decoder.ResolveSampleRate(dec.SampleRate(), meta)

	const chunkFrames = 1024
	buf := make([]float32, chunkFrames*channels)
	seq := uint64(0)

	for {
		select {
		case <-ctx.Done():
			return nil
		default:
		}

		n, readErr := dec.Read(buf)
		if n > 0 {
			chunk := decoder.BuildChunk(
				decoder.Float32ToPCM32(buf[:n]),
				channels,
				sampleRate,
				seq,
				meta.SourceID,
			)
			if err := emit(chunk); err != nil {
				return err
			}
			seq++
		}

		if readErr != nil {
			if readErr == io.EOF {
				return nil
			}
			return fmt.Errorf("ogg/vorbis decoder read pcm: %w", readErr)
		}
	}
}
