package logging

import (
	"errors"
	"io"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)

var errTestSink = errors.New("sink failed")

type failingWriteCloser struct{}

func (failingWriteCloser) Write([]byte) (int, error) { return 0, errTestSink }
func (failingWriteCloser) Close() error              { return nil }

type discardWriteCloser struct{}

func (discardWriteCloser) Write(data []byte) (int, error) { return len(data), nil }
func (discardWriteCloser) Close() error                   { return nil }

type failingCloseWriteCloser struct{}

func (failingCloseWriteCloser) Write(data []byte) (int, error) { return len(data), nil }
func (failingCloseWriteCloser) Close() error                   { return errTestSink }

func TestFileSinkPropagatesBufferedWriterFailuresOnClose(t *testing.T) {
	sink := newFileSink(failingWriteCloser{}, 1024, time.Hour)
	written, err := sink.Write([]byte("buffered"))
	require.NoError(t, err)
	require.Equal(t, len("buffered"), written)

	require.ErrorIs(t, sink.Flush(), errTestSink)
	require.ErrorIs(t, sink.Close(), errTestSink)
}

func TestFileSinkRetainsOnlyFirstWriterFailure(t *testing.T) {
	sink := newFileSink(failingWriteCloser{}, 1024, time.Hour)
	_, err := sink.Write([]byte("buffered"))
	require.NoError(t, err)

	for range 1000 {
		err = sink.Flush()
	}
	require.EqualError(t, err, errTestSink.Error())
	require.EqualError(t, sink.Close(), errTestSink.Error())
}

func TestFileSinkRejectsBufferedWritesAndFlushesAfterClose(t *testing.T) {
	sink := newFileSink(discardWriteCloser{}, 1024, time.Hour)
	require.NoError(t, sink.Close())

	written, err := sink.Write([]byte("lost"))
	require.Zero(t, written)
	require.ErrorIs(t, err, io.ErrClosedPipe)
	require.ErrorIs(t, sink.Flush(), io.ErrClosedPipe)
}

func TestFileSinkPropagatesWriterCloseFailure(t *testing.T) {
	sink := newFileSink(failingCloseWriteCloser{}, 0, time.Hour)
	require.ErrorIs(t, sink.Close(), errTestSink)
}
