package meta

import (
	"context"
	"errors"
	"math"
	"strings"
	"testing"
)

func TestTenantEmbeddingConfigCRUD(t *testing.T) {
	s, cleanup := newTestStore(t)
	defer cleanup()
	ctx := context.Background()

	if _, err := s.GetTenantEmbeddingConfig(ctx, "embed-config-tenant"); !errors.Is(err, ErrNotFound) {
		t.Fatalf("absent config error = %v, want %v", err, ErrNotFound)
	}
	cfg := &TenantEmbeddingConfig{
		TenantID:       "embed-config-tenant",
		Enabled:        true,
		APIBase:        "https://api.example.com/v1",
		APIKeyCipher:   []byte("cipher"),
		Model:          "embed-model",
		Generation:     3,
		ConfigRevision: 5,
	}
	if err := s.UpsertTenantEmbeddingConfig(ctx, cfg); err != nil {
		t.Fatal(err)
	}
	got, err := s.GetTenantEmbeddingConfig(ctx, cfg.TenantID)
	if err != nil {
		t.Fatal(err)
	}
	if !got.Enabled || got.APIBase != cfg.APIBase || string(got.APIKeyCipher) != "cipher" ||
		got.Model != cfg.Model || got.Generation != 3 || got.ConfigRevision != 5 {
		t.Fatalf("config = %+v", got)
	}

	cfg.Enabled = false
	cfg.APIBase = ""
	cfg.APIKeyCipher = nil
	cfg.Model = ""
	cfg.Generation = 4
	cfg.ConfigRevision = 6
	if err := s.UpsertTenantEmbeddingConfig(ctx, cfg); err != nil {
		t.Fatal(err)
	}
	got, err = s.GetTenantEmbeddingConfig(ctx, cfg.TenantID)
	if err != nil {
		t.Fatal(err)
	}
	if got.Enabled || got.APIBase != "" || got.APIKeyCipher != nil || got.Model != "" ||
		got.Generation != 4 || got.ConfigRevision != 6 {
		t.Fatalf("off marker = %+v", got)
	}

	if err := s.DeleteTenantEmbeddingConfig(ctx, cfg.TenantID); err != nil {
		t.Fatal(err)
	}
	if _, err := s.GetTenantEmbeddingConfig(ctx, cfg.TenantID); !errors.Is(err, ErrNotFound) {
		t.Fatalf("deleted config error = %v, want %v", err, ErrNotFound)
	}
}

func TestTenantEmbeddingConfigRejectsInvalidShape(t *testing.T) {
	s, cleanup := newTestStore(t)
	defer cleanup()
	ctx := context.Background()

	for _, cfg := range []*TenantEmbeddingConfig{
		nil,
		{},
		{TenantID: "tenant", Enabled: true, APIBase: "", APIKeyCipher: []byte("cipher"), Model: "m", Generation: 1, ConfigRevision: 1},
		{TenantID: "tenant", Enabled: false, APIBase: "https://example.com", Generation: 1, ConfigRevision: 1},
		{TenantID: "tenant", Generation: 0, ConfigRevision: 1},
		{TenantID: "tenant", Generation: 1, ConfigRevision: 0},
		{TenantID: "tenant", Generation: uint64(math.MaxInt64) + 1, ConfigRevision: 1},
		{TenantID: "tenant", Generation: 1, ConfigRevision: uint64(math.MaxInt64) + 1},
	} {
		if err := s.UpsertTenantEmbeddingConfig(ctx, cfg); err == nil {
			t.Fatalf("UpsertTenantEmbeddingConfig(%+v) succeeded", cfg)
		}
	}
}

func TestTenantEmbeddingConfigRejectsProviderFieldsBeyondSchemaLimits(t *testing.T) {
	base := TenantEmbeddingConfig{
		TenantID: "tenant", Enabled: true, APIBase: "https://example.com",
		APIKeyCipher: []byte("cipher"), Model: "model", Generation: 1, ConfigRevision: 1,
	}
	for _, tc := range []struct {
		name   string
		mutate func(*TenantEmbeddingConfig)
	}{
		{name: "api base", mutate: func(cfg *TenantEmbeddingConfig) { cfg.APIBase = strings.Repeat("a", TenantEmbeddingAPIBaseMaxChars+1) }},
		{name: "api key cipher", mutate: func(cfg *TenantEmbeddingConfig) {
			cfg.APIKeyCipher = make([]byte, TenantEmbeddingAPIKeyCipherMaxBytes+1)
		}},
		{name: "model", mutate: func(cfg *TenantEmbeddingConfig) { cfg.Model = strings.Repeat("m", TenantEmbeddingModelMaxChars+1) }},
	} {
		t.Run(tc.name, func(t *testing.T) {
			cfg := base
			tc.mutate(&cfg)
			if err := validateTenantEmbeddingConfig(&cfg); err == nil {
				t.Fatal("oversized provider field was accepted")
			}
		})
	}
}
