package runtimeapi

import (
	"context"
	"errors"
	"testing"

	catalogsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/catalog/consumerv1"
	recordsemantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/recordsv1"
)

func TestCatalogConsumerAdmissionBindsExactWorkloadAndInstallation(t *testing.T) {
	admission, err := NewCatalogConsumerAdmission(
		[]CatalogConsumerSelection{
			{
				OrgID: "org-1", AppInstallationID: "installation-1",
				WorkloadID:   "integration-service",
				CapabilityID: catalogsemantic.IntegrationBindingCapabilityName,
			},
			{
				OrgID: "org-1", AppInstallationID: "installation-1",
				WorkloadID:   "sfcrm-app-service",
				CapabilityID: catalogsemantic.AppMetadataV2CapabilityName,
			},
		},
	)
	if err != nil {
		t.Fatal(err)
	}
	ctx := context.WithValue(
		t.Context(),
		trustedWorkloadCallContextKey{},
		TrustedWorkloadCall{
			orgID: "org-1", callerWorkloadID: "integration-service",
			capability:    catalogsemantic.IntegrationBindingCapabilityName,
			securityEpoch: 7,
		},
	)
	bound, err := admission.bind(
		ctx,
		catalogsemantic.IntegrationBindingCapabilityName,
	)
	if err != nil {
		t.Fatal(err)
	}
	scope, ok := catalogConsumerScopeFromAdmission(
		bound,
		catalogsemantic.IntegrationBindingCapabilityName,
	)
	if !ok || scope.OrgID != "org-1" ||
		scope.AppInstallationID != "installation-1" ||
		scope.WorkloadID != "integration-service" {
		t.Fatalf("Catalog consumer scope = %#v, %v", scope, ok)
	}
	// The shared serving interceptor may bypass RuntimeMetadataView admission
	// only after this exact Catalog consumer scope has been established.
	serving := &ServingAdmission{}
	if admitted, err := serving.bind(
		bound,
		catalogsemantic.IntegrationBindingCapabilityName,
	); err != nil || admitted != bound {
		t.Fatalf("Catalog consumer serving handoff = %v, %v", admitted, err)
	}
	if _, err := serving.bind(
		bound,
		catalogsemantic.AppMetadataV2CapabilityName,
	); err == nil {
		t.Fatal("Catalog consumer scope bypassed a different capability")
	}

	for name, mutate := range map[string]func(*TrustedWorkloadCall){
		"wrong workload": func(call *TrustedWorkloadCall) {
			call.callerWorkloadID = "sfcrm-app-service"
		},
		"wrong org": func(call *TrustedWorkloadCall) {
			call.orgID = "org-2"
		},
	} {
		t.Run(name, func(t *testing.T) {
			call := TrustedWorkloadCall{
				orgID: "org-1", callerWorkloadID: "integration-service",
				capability:    catalogsemantic.IntegrationBindingCapabilityName,
				securityEpoch: 7,
			}
			mutate(&call)
			_, err := admission.bind(
				context.WithValue(
					t.Context(),
					trustedWorkloadCallContextKey{},
					call,
				),
				catalogsemantic.IntegrationBindingCapabilityName,
			)
			var failure *recordsemantic.Failure
			if !errors.As(err, &failure) {
				t.Fatalf("error = %v", err)
			}
			if failure.Category != recordsemantic.FailureForbidden {
				t.Fatalf("scope error = %#v", failure)
			}
		})
	}

	// SecurityAdmission is the sole current SecurityEpoch owner. Once it has
	// authenticated and stamped a call, Catalog disclosure must not compare
	// against a second startup-time epoch snapshot.
	rotated := context.WithValue(
		t.Context(),
		trustedWorkloadCallContextKey{},
		TrustedWorkloadCall{
			orgID: "org-1", callerWorkloadID: "integration-service",
			capability:    catalogsemantic.IntegrationBindingCapabilityName,
			securityEpoch: 8,
		},
	)
	if _, err := admission.bind(
		rotated,
		catalogsemantic.IntegrationBindingCapabilityName,
	); err != nil {
		t.Fatalf("current rotated SecurityEpoch was rejected: %v", err)
	}
}
