package stream

import (
	"io"
	"os"
	"sync"
)

// pipeReader bridges io.Reader to a file descriptor that can be used as FFmpeg input
type pipeReader struct {
	r   io.Reader
	pr  *io.PipeReader
	pw  *io.PipeWriter
	f   *os.File
	err error
	mu  sync.Mutex
}

// newPipeReader creates a new pipe reader that bridges io.Reader to a pipe
func newPipeReader(r io.Reader) (*pipeReader, error) {
	pr, pw := io.Pipe()
	return &pipeReader{
		r:  r,
		pr: pr,
		pw: pw,
	}, nil
}

// start begins copying data from the underlying reader to the pipe in background
func (p *pipeReader) start() {
	go func() {
		buf := make([]byte, 32768)
		for {
			n, err := p.r.Read(buf)
			if n > 0 {
				_, writeErr := p.pw.Write(buf[:n])
				if writeErr != nil {
					p.mu.Lock()
					p.err = writeErr
					p.mu.Unlock()
					p.pw.CloseWithError(writeErr)
					return
				}
			}
			if err != nil {
				p.pw.CloseWithError(err)
				return
			}
		}
	}()
}

// Read implements io.Reader
func (p *pipeReader) Read(data []byte) (n int, err error) {
	return p.pr.Read(data)
}

// Close closes the pipe
func (p *pipeReader) Close() error {
	err := p.pr.Close()
	p.pw.Close()
	return err
}

// Error returns any error that occurred during reading
func (p *pipeReader) Error() error {
	p.mu.Lock()
	defer p.mu.Unlock()
	return p.err
}
