package oto

import (
	"fmt"

	"github.com/hajimehoshi/oto"
	"github.com/vsariola/sointu"
)

type OtoContext oto.Context
type OtoOutput struct {
	player    *oto.Player
	tmpBuffer []byte
}

func (c *OtoContext) Output() sointu.AudioOutput {
	return &OtoOutput{player: (*oto.Context)(c).NewPlayer(), tmpBuffer: make([]byte, 0)}
}

const otoBufferSize = 8192

// NewPlayer creates and initializes a new OtoPlayer
func NewContext() (*OtoContext, error) {
	context, err := oto.NewContext(44100, 2, 2, otoBufferSize)
	if err != nil {
		return nil, fmt.Errorf("cannot create oto context: %w", err)
	}
	return (*OtoContext)(context), nil
}

func (c *OtoContext) Close() error {
	if err := (*oto.Context)(c).Close(); err != nil {
		return fmt.Errorf("cannot close oto context: %w", err)
	}
	return nil
}

// Play implements the audio.Player interface for OtoPlayer
func (o *OtoOutput) WriteAudio(floatBuffer sointu.AudioBuffer) (err error) {
	// we reuse the old capacity tmpBuffer by setting its length to zero. then,
	// we save the tmpBuffer so we can reuse it next time
	o.tmpBuffer = FloatBufferTo16BitLE(floatBuffer, o.tmpBuffer[:0])
	if _, err := o.player.Write(o.tmpBuffer); err != nil {
		return fmt.Errorf("cannot write to player: %w", err)
	}
	return nil
}

// Close disposes of resources
func (o *OtoOutput) Close() error {
	if err := o.player.Close(); err != nil {
		return fmt.Errorf("cannot close oto player: %w", err)
	}
	return nil
}
