package server

import (
	"context"
	"testing"

	"gorm.io/gorm"

	"github.com/pingcap/agent-git-service/config"
	"github.com/pingcap/agent-git-service/internal/crypto"
	"github.com/pingcap/agent-git-service/internal/embedding"
	"github.com/pingcap/agent-git-service/internal/gitstore"
	"github.com/pingcap/agent-git-service/internal/service"
	"github.com/pingcap/agent-git-service/internal/tenant"
	"github.com/pingcap/agent-git-service/internal/wikicatalog"
)

type tenantServiceTestFixture struct {
	registry *tenantRegistry
	deps     serviceDeps
	ctx      context.Context
	cancel   context.CancelFunc
}

func newTenantServiceTestFixture(t *testing.T, cfg config.Config) *tenantServiceTestFixture {
	t.Helper()

	normalized, err := config.Normalize(cfg)
	if err != nil {
		t.Fatalf("normalize config: %v", err)
	}
	core, err := initCoreDepsFromConfig(normalized)
	if err != nil {
		t.Fatalf("initialize tenant registry: %v", err)
	}

	srvCtx, srvCancel := context.WithCancel(context.Background())
	deps, err := initTenantServiceDeps(core.registry, core.store, srvCtx)
	if err != nil {
		srvCancel()
		core.registry.close()
		t.Fatalf("initialize tenant service: %v", err)
	}

	fixture := &tenantServiceTestFixture{
		registry: core.registry,
		deps:     deps,
		ctx:      srvCtx,
		cancel:   srvCancel,
	}
	t.Cleanup(func() {
		fixture.cancel()
		fixture.deps.svc.Wg.Wait()
		fixture.registry.close()
	})
	return fixture
}

func (f *tenantServiceTestFixture) tenant(t *testing.T, id tenant.ID) (context.Context, *service.TenantResources) {
	t.Helper()
	resources, err := f.registry.ForTenant(id)
	if err != nil {
		t.Fatalf("tenant %q resources: %v", id, err)
	}
	return tenant.WithInfo(f.ctx, resources.Info), resources
}

func newLifecycleTestService(t *testing.T, srvCtx context.Context) (*service.Service, *tenantRegistry, context.Context) {
	t.Helper()
	info := tenant.Info{
		ID:               "lifecycle-test",
		CanonicalBaseURL: "https://lifecycle.example.test",
	}
	database := &gorm.DB{Config: &gorm.Config{}}
	git, err := gitstore.NewForTenant(t.TempDir(), info.ID)
	if err != nil {
		t.Fatalf("initialize lifecycle git store: %v", err)
	}
	wikiBlob := wikicatalog.NewBlobStore(t.TempDir())
	secretBox, err := crypto.NewSecretBox("")
	if err != nil {
		t.Fatalf("initialize lifecycle secret box: %v", err)
	}
	resources := &service.TenantResources{
		Info:        info,
		DB:          database,
		Git:         git,
		WikiCatalog: wikicatalog.New(database, wikiBlob),
		WikiBlob:    wikiBlob,
		SecretBox:   secretBox,
		Embedder:    embedding.NopEmbedder{},
	}
	if err := resources.Validate(); err != nil {
		t.Fatalf("validate lifecycle tenant resources: %v", err)
	}
	registry := &tenantRegistry{
		ids: []tenant.ID{info.ID},
		byID: map[tenant.ID]*service.TenantResources{
			info.ID: resources,
		},
	}
	svc, err := service.NewService(srvCtx, registry)
	if err != nil {
		t.Fatalf("initialize lifecycle service: %v", err)
	}
	return svc, registry, tenant.WithInfo(srvCtx, info)
}
