package llm

import (
	"context"
	"errors"
	"sync/atomic"
	"testing"

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

type fakeEndpoint struct {
	ID       uuid.UUID
	Provider string
	BaseURL  string
	APIKey   string
}

type fakeLoader struct {
	endpoints map[uuid.UUID]fakeEndpoint
	calls     int32
}

func (l *fakeLoader) Load(ctx context.Context, id uuid.UUID) (Endpoint, error) {
	atomic.AddInt32(&l.calls, 1)
	ep, ok := l.endpoints[id]
	if !ok {
		return Endpoint{}, errors.New("not found")
	}
	return Endpoint{ID: ep.ID, Provider: ep.Provider, BaseURL: ep.BaseURL, APIKey: ep.APIKey}, nil
}

func TestRegistry_CachesByEndpointID(t *testing.T) {
	id := uuid.New()
	loader := &fakeLoader{endpoints: map[uuid.UUID]fakeEndpoint{
		id: {ID: id, Provider: "anthropic", BaseURL: "http://localhost", APIKey: "k"},
	}}
	r := NewRegistry(loader)

	c1, err := r.GetClient(context.Background(), id)
	require.NoError(t, err)
	c2, err := r.GetClient(context.Background(), id)
	require.NoError(t, err)
	require.Same(t, c1, c2)
	require.Equal(t, int32(1), atomic.LoadInt32(&loader.calls))
}

func TestRegistry_InvalidateForcesReload(t *testing.T) {
	id := uuid.New()
	loader := &fakeLoader{endpoints: map[uuid.UUID]fakeEndpoint{
		id: {ID: id, Provider: "anthropic", BaseURL: "http://localhost", APIKey: "k"},
	}}
	r := NewRegistry(loader)
	_, err := r.GetClient(context.Background(), id)
	require.NoError(t, err)
	r.Invalidate(id)
	_, err = r.GetClient(context.Background(), id)
	require.NoError(t, err)
	require.Equal(t, int32(2), atomic.LoadInt32(&loader.calls))
}

func TestRegistry_UnknownProviderReturnsError(t *testing.T) {
	id := uuid.New()
	loader := &fakeLoader{endpoints: map[uuid.UUID]fakeEndpoint{
		id: {ID: id, Provider: "claude-3-but-typoed"},
	}}
	r := NewRegistry(loader)
	_, err := r.GetClient(context.Background(), id)
	require.Error(t, err)
}

func TestRegistry_LoaderErrorPropagates(t *testing.T) {
	loader := &fakeLoader{endpoints: map[uuid.UUID]fakeEndpoint{}}
	r := NewRegistry(loader)
	_, err := r.GetClient(context.Background(), uuid.New())
	require.Error(t, err)
}
