package conversion

import (
	"fmt"
	"testing"

	"nex/backend/internal/conversion/canonical"

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

func TestPassthroughStreamConverter_ProcessChunk(t *testing.T) {
	converter := NewPassthroughStreamConverter()
	data := []byte("hello world")
	result := converter.ProcessChunk(data)
	assert.Len(t, result, 1)
	assert.Equal(t, data, result[0])
}

func TestPassthroughStreamConverter_Flush(t *testing.T) {
	converter := NewPassthroughStreamConverter()
	result := converter.Flush()
	assert.Nil(t, result)
}

// mockStreamDecoder 模拟流式解码器
type mockStreamDecoder struct {
	chunks [][]canonical.CanonicalStreamEvent
	flush  []canonical.CanonicalStreamEvent
}

// ProcessChunk 弹出下一个分片的事件
func (d *mockStreamDecoder) ProcessChunk(rawChunk []byte) []canonical.CanonicalStreamEvent {
	if len(d.chunks) == 0 {
		return nil
	}
	events := d.chunks[0]
	d.chunks = d.chunks[1:]
	return events
}

// Flush 返回刷新事件
func (d *mockStreamDecoder) Flush() []canonical.CanonicalStreamEvent {
	return d.flush
}

// mockStreamEncoder 模拟流式编码器
type mockStreamEncoder struct {
	events [][]byte
	flush  [][]byte
}

// EncodeEvent 返回编码后的事件
func (e *mockStreamEncoder) EncodeEvent(event canonical.CanonicalStreamEvent) [][]byte {
	if len(e.events) == 0 {
		return nil
	}
	return e.events
}

// Flush 返回编码器刷新数据
func (e *mockStreamEncoder) Flush() [][]byte {
	return e.flush
}

func TestCanonicalStreamConverter_ProcessChunk(t *testing.T) {
	event := canonical.NewMessageStartEvent("id-1", "gpt-4")
	decoder := &mockStreamDecoder{
		chunks: [][]canonical.CanonicalStreamEvent{{event}},
	}
	encoder := &mockStreamEncoder{
		events: [][]byte{[]byte("data: test\n\n")},
	}

	converter := NewCanonicalStreamConverter(decoder, encoder)
	result := converter.ProcessChunk([]byte("raw"))

	assert.Len(t, result, 1)
	assert.Equal(t, []byte("data: test\n\n"), result[0])
}

func TestCanonicalStreamConverter_WithMiddleware(t *testing.T) {
	var records []string
	event := canonical.NewMessageStartEvent("id-1", "gpt-4")
	decoder := &mockStreamDecoder{
		chunks: [][]canonical.CanonicalStreamEvent{{event}},
	}
	encoder := &mockStreamEncoder{
		events: [][]byte{[]byte("data: ok\n\n")},
	}

	chain := NewMiddlewareChain()
	chain.Use(&recordingMiddleware{name: "mw1", records: &records})
	ctx := NewConversionContext(InterfaceTypeChat)

	converter := NewCanonicalStreamConverterWithMiddleware(decoder, encoder, chain, *ctx, "openai", "anthropic", "")
	result := converter.ProcessChunk([]byte("raw"))

	assert.Len(t, result, 1)
	assert.Equal(t, []string{"stream:mw1"}, records)
	assert.Equal(t, []byte("data: ok\n\n"), result[0])
}

func TestCanonicalStreamConverter_Flush(t *testing.T) {
	decoder := &mockStreamDecoder{
		flush: []canonical.CanonicalStreamEvent{
			canonical.NewMessageStopEvent(),
		},
	}
	encoder := &mockStreamEncoder{
		events: [][]byte{[]byte("data: stop\n\n")},
		flush:  [][]byte{[]byte("data: flush\n\n")},
	}

	converter := NewCanonicalStreamConverter(decoder, encoder)
	result := converter.Flush()

	assert.Len(t, result, 2)
	assert.Equal(t, []byte("data: stop\n\n"), result[0])
	assert.Equal(t, []byte("data: flush\n\n"), result[1])
}

func TestCanonicalStreamConverter_EmptyDecoder(t *testing.T) {
	decoder := &mockStreamDecoder{}
	encoder := &mockStreamEncoder{}

	converter := NewCanonicalStreamConverter(decoder, encoder)
	result := converter.ProcessChunk([]byte("raw"))

	assert.Nil(t, result)
}

func TestCanonicalStreamConverter_MiddlewareError_Continue(t *testing.T) {
	event := canonical.NewMessageStartEvent("id-1", "gpt-4")
	decoder := &mockStreamDecoder{
		chunks: [][]canonical.CanonicalStreamEvent{{event}},
	}
	encoder := &mockStreamEncoder{
		events: [][]byte{[]byte("data: ok\n\n")},
	}

	chain := NewMiddlewareChain()
	chain.Use(&errorMiddleware{})
	ctx := NewConversionContext(InterfaceTypeChat)

	converter := NewCanonicalStreamConverterWithMiddleware(decoder, encoder, chain, *ctx, "openai", "anthropic", "")
	result := converter.ProcessChunk([]byte("raw"))

	assert.Nil(t, result, "middleware error should cause the event to be skipped (continue)")
}

func TestCanonicalStreamConverter_Flush_MiddlewareError_Continue(t *testing.T) {
	event := canonical.NewMessageStartEvent("id-1", "gpt-4")
	decoder := &mockStreamDecoder{
		flush: []canonical.CanonicalStreamEvent{event},
	}
	encoder := &mockStreamEncoder{
		events: [][]byte{[]byte("data: ok\n\n")},
		flush:  [][]byte{[]byte("data: encoder_flush\n\n")},
	}

	chain := NewMiddlewareChain()
	chain.Use(&errorMiddleware{})
	ctx := NewConversionContext(InterfaceTypeChat)

	converter := NewCanonicalStreamConverterWithMiddleware(decoder, encoder, chain, *ctx, "openai", "anthropic", "")
	result := converter.Flush()

	assert.Len(t, result, 1)
	assert.Equal(t, []byte("data: encoder_flush\n\n"), result[0])
}

func TestCanonicalStreamConverter_Flush_DecoderAndEncoderBothProduce(t *testing.T) {
	event := canonical.NewMessageStartEvent("id-1", "gpt-4")
	decoder := &mockStreamDecoder{
		flush: []canonical.CanonicalStreamEvent{event},
	}
	encoder := &mockStreamEncoder{
		events: [][]byte{[]byte("data: decoder_flush\n\n")},
		flush:  [][]byte{[]byte("data: encoder_flush\n\n")},
	}

	converter := NewCanonicalStreamConverter(decoder, encoder)
	result := converter.Flush()

	assert.Len(t, result, 2)
	assert.Equal(t, []byte("data: decoder_flush\n\n"), result[0])
	assert.Equal(t, []byte("data: encoder_flush\n\n"), result[1])
}

type errorMiddleware struct{}

func (m *errorMiddleware) Intercept(req *canonical.CanonicalRequest, clientProtocol, providerProtocol string, ctx *ConversionContext) (*canonical.CanonicalRequest, error) {
	return nil, fmt.Errorf("middleware error")
}

func (m *errorMiddleware) InterceptStreamEvent(event *canonical.CanonicalStreamEvent, clientProtocol, providerProtocol string, ctx *ConversionContext) (*canonical.CanonicalStreamEvent, error) {
	return nil, fmt.Errorf("stream middleware error")
}
