package acceptancesnapshot

import (
	"encoding/json"
	"testing"
	"time"
)

func TestSnapshotValidationRejectsSecretsAndDetectsTampering(t *testing.T) {
	snapshot := validSnapshot(t)
	if err := Validate(snapshot); err != nil {
		t.Fatalf("validate fixture: %v", err)
	}

	tampered := snapshot
	tampered.Candidates = append([]Candidate(nil), snapshot.Candidates...)
	tampered.Candidates[0].Platform.Name = "tampered"
	if err := Validate(tampered); err == nil {
		t.Fatal("tampered snapshot passed validation")
	}

	unsafe := snapshot
	unsafe.Candidates = append([]Candidate(nil), snapshot.Candidates...)
	unsafe.Candidates[0].Platform.Config = map[string]any{"apiToken": "must-not-leak"}
	refreshHashes(t, &unsafe)
	if err := Validate(unsafe); err == nil {
		t.Fatal("secret-like snapshot field passed validation")
	}
}

func TestSanitizeMapRemovesCredentialAndProxyFields(t *testing.T) {
	input := map[string]any{
		"specType":      "gemini",
		"credentialEnv": "PRODUCTION_TOKEN",
		"networkProxy": map[string]any{
			"proxyUrl": "http://user:password@example.invalid",
		},
		"requestAssetImageURLFormat": "base64",
	}
	got := sanitizeMap(input)
	if got["specType"] != "gemini" || got["requestAssetImageURLFormat"] != "base64" {
		t.Fatalf("safe protocol fields were removed: %#v", got)
	}
	if _, ok := got["credentialEnv"]; ok {
		t.Fatal("credentialEnv was not removed")
	}
	nested, _ := got["networkProxy"].(map[string]any)
	if _, ok := nested["proxyUrl"]; ok {
		t.Fatal("nested proxy URL was not removed")
	}
}

func TestDecodeRejectsUnknownSnapshotFields(t *testing.T) {
	snapshot := validSnapshot(t)
	payload, err := json.Marshal(snapshot)
	if err != nil {
		t.Fatal(err)
	}
	var object map[string]any
	if err := json.Unmarshal(payload, &object); err != nil {
		t.Fatal(err)
	}
	object["unexpected"] = true
	payload, _ = json.Marshal(object)
	if _, err := Decode(payload); err == nil {
		t.Fatal("snapshot with unknown field decoded successfully")
	}
}

func validSnapshot(t *testing.T) Snapshot {
	t.Helper()
	candidates := []Candidate{
		{
			Workload: "gemini_image_edit",
			Provider: Provider{
				ProviderKey: "gemini", ProviderCode: "google-gemini",
				DisplayName: "Gemini", ProviderType: "gemini",
				CapabilitySchema: map[string]any{}, DefaultRateLimitPolicy: map[string]any{},
			},
			BaseModel: BaseModel{
				CanonicalModelKey: "gemini:image", InvocationName: "gemini-image",
				ProviderModelName: "gemini-image", ModelType: []string{"image_edit"},
				DisplayName: "Gemini Image", Capabilities: map[string]any{},
				BaseBillingConfig: map[string]any{}, DefaultRateLimitPolicy: map[string]any{},
				RuntimePolicyOverride: map[string]any{}, PricingVersion: 1,
			},
			Platform: Platform{
				Provider: "gemini", PlatformKey: "gemini-production", Name: "Gemini Production",
				BaseURLPath: "/", AuthType: "api_key", Config: map[string]any{"specType": "gemini"},
				DefaultPricingMode: "inherit_discount", DefaultDiscountFactor: "1",
				RetryPolicy: map[string]any{}, RateLimitPolicy: map[string]any{}, Priority: 10,
			},
			PlatformModel: PlatformModel{
				ModelName: "gemini-image", ProviderModelName: "gemini-image",
				ModelType: []string{"image_edit"}, DisplayName: "Gemini Image",
				CapabilityOverride: map[string]any{}, Capabilities: map[string]any{},
				PricingMode: "inherit_discount", BillingConfigOverride: map[string]any{},
				BillingConfig: map[string]any{}, PermissionConfig: map[string]any{},
				RetryPolicy: map[string]any{}, RateLimitPolicy: map[string]any{},
				RuntimePolicyOverride: map[string]any{},
			},
			RuntimePolicy: RuntimePolicy{
				RateLimitPolicy: map[string]any{}, RetryPolicy: map[string]any{},
				AutoDisablePolicy: map[string]any{}, DegradePolicy: map[string]any{},
			},
			PricingRules: []PricingRule{},
			Metadata: CandidateSource{
				PlatformID:      "00000000-0000-0000-0000-000000000001",
				PlatformModelID: "00000000-0000-0000-0000-000000000002",
				BaseModelID:     "00000000-0000-0000-0000-000000000003",
			},
		},
		{
			Workload: "multi_reference_video",
			Provider: Provider{
				ProviderKey: "volces", ProviderCode: "volces",
				DisplayName: "Volces", ProviderType: "volces",
				CapabilitySchema: map[string]any{}, DefaultRateLimitPolicy: map[string]any{},
			},
			BaseModel: BaseModel{
				CanonicalModelKey: "volces:seedance", InvocationName: "seedance-2-fast",
				ProviderModelName: "seedance-2-fast", ModelType: []string{"omni_video"},
				DisplayName: "Seedance", Capabilities: map[string]any{"omni_video": map[string]any{"max_images": 9}},
				BaseBillingConfig: map[string]any{}, DefaultRateLimitPolicy: map[string]any{},
				RuntimePolicyOverride: map[string]any{}, PricingVersion: 1,
			},
			Platform: Platform{
				Provider: "volces", PlatformKey: "volces-production", Name: "Volces Production",
				BaseURLPath: "/", AuthType: "bearer", Config: map[string]any{"specType": "volces"},
				DefaultPricingMode: "inherit_discount", DefaultDiscountFactor: "1",
				RetryPolicy: map[string]any{}, RateLimitPolicy: map[string]any{}, Priority: 10,
			},
			PlatformModel: PlatformModel{
				ModelName: "seedance-2-fast", ProviderModelName: "seedance-2-fast",
				ModelType: []string{"omni_video"}, DisplayName: "Seedance",
				CapabilityOverride: map[string]any{"omni_video": map[string]any{"max_images": 9}},
				Capabilities:       map[string]any{}, PricingMode: "inherit_discount",
				BillingConfigOverride: map[string]any{}, BillingConfig: map[string]any{},
				PermissionConfig: map[string]any{}, RetryPolicy: map[string]any{},
				RateLimitPolicy: map[string]any{}, RuntimePolicyOverride: map[string]any{},
			},
			RuntimePolicy: RuntimePolicy{
				RateLimitPolicy: map[string]any{}, RetryPolicy: map[string]any{},
				AutoDisablePolicy: map[string]any{}, DegradePolicy: map[string]any{},
			},
			PricingRules: []PricingRule{},
			Metadata: CandidateSource{
				PlatformID:      "00000000-0000-0000-0000-000000000004",
				PlatformModelID: "00000000-0000-0000-0000-000000000005",
				BaseModelID:     "00000000-0000-0000-0000-000000000006",
			},
		},
	}
	snapshot := Snapshot{
		SchemaVersion: SchemaVersion,
		Source: Source{
			ReleaseSHA: "0123456789abcdef0123456789abcdef01234567",
			CreatedAt:  time.Date(2026, 7, 31, 0, 0, 0, 0, time.UTC),
		},
		Candidates: candidates,
		SecretSafe: true,
	}
	refreshHashes(t, &snapshot)
	return snapshot
}

func refreshHashes(t *testing.T, snapshot *Snapshot) {
	t.Helper()
	configHash, err := candidateConfigHash(snapshot.Candidates)
	if err != nil {
		t.Fatal(err)
	}
	snapshot.Source.ConfigHash = configHash
	snapshot.SnapshotSHA256 = ""
	hash, err := snapshotHash(*snapshot)
	if err != nil {
		t.Fatal(err)
	}
	snapshot.SnapshotSHA256 = hash
}
