package conversion

import (
	"errors"
	"testing"

	"nex/backend/internal/conversion/canonical"

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

// recordingMiddleware 记录调用顺序的中间件
type recordingMiddleware struct {
	name    string
	records *[]string
	err     error
}

func (m *recordingMiddleware) Intercept(req *canonical.CanonicalRequest, clientProtocol, providerProtocol string, ctx *ConversionContext) (*canonical.CanonicalRequest, error) {
	*m.records = append(*m.records, m.name)
	if m.err != nil {
		return nil, m.err
	}
	return req, nil
}

func (m *recordingMiddleware) InterceptStreamEvent(event *canonical.CanonicalStreamEvent, clientProtocol, providerProtocol string, ctx *ConversionContext) (*canonical.CanonicalStreamEvent, error) {
	*m.records = append(*m.records, "stream:"+m.name)
	if m.err != nil {
		return nil, m.err
	}
	return event, nil
}

func TestMiddlewareChain_Empty(t *testing.T) {
	chain := NewMiddlewareChain()
	req := &canonical.CanonicalRequest{Model: "test"}
	ctx := NewConversionContext(InterfaceTypeChat)

	result, err := chain.Apply(req, "a", "b", ctx)
	assert.NoError(t, err)
	assert.Equal(t, "test", result.Model)
}

func TestMiddlewareChain_Order(t *testing.T) {
	var records []string
	chain := NewMiddlewareChain()
	chain.Use(&recordingMiddleware{name: "first", records: &records})
	chain.Use(&recordingMiddleware{name: "second", records: &records})
	chain.Use(&recordingMiddleware{name: "third", records: &records})

	req := &canonical.CanonicalRequest{Model: "test"}
	ctx := NewConversionContext(InterfaceTypeChat)
	_, err := chain.Apply(req, "a", "b", ctx)
	assert.NoError(t, err)
	assert.Equal(t, []string{"first", "second", "third"}, records)
}

func TestMiddlewareChain_ErrorInterrupt(t *testing.T) {
	var records []string
	chain := NewMiddlewareChain()
	chain.Use(&recordingMiddleware{name: "first", records: &records})
	chain.Use(&recordingMiddleware{name: "second", records: &records, err: errors.New("中断")})
	chain.Use(&recordingMiddleware{name: "third", records: &records})

	req := &canonical.CanonicalRequest{Model: "test"}
	ctx := NewConversionContext(InterfaceTypeChat)
	_, err := chain.Apply(req, "a", "b", ctx)
	assert.Error(t, err)
	assert.Equal(t, "中断", err.Error())
	assert.Equal(t, []string{"first", "second"}, records)
}

func TestMiddlewareChain_ApplyStreamEvent(t *testing.T) {
	var records []string
	chain := NewMiddlewareChain()
	chain.Use(&recordingMiddleware{name: "mw1", records: &records})

	event := canonical.NewMessageStartEvent("id", "model")
	ctx := NewConversionContext(InterfaceTypeChat)
	result, err := chain.ApplyStreamEvent(&event, "a", "b", ctx)
	assert.NoError(t, err)
	assert.Equal(t, canonical.EventMessageStart, result.Type)
	assert.Equal(t, []string{"stream:mw1"}, records)
}
