package registry

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/extension/spec"
)

// Blocker #1 — RegisterExternal must run the FULL shared Definition validation,
// not just re-verify the digest. The adversarial cases below construct an
// INVALID package (content a V1 loader rejects), then RE-SIGN it with a fresh
// self-consistent digest, and confirm RegisterExternal still rejects it. A
// digest-only check would accept these because the digest matches the
// (invalid) content; the full loader validation catches the invalid content.

// Adversarial: a package whose binding.method is TRACE (rejected by the V1
// closed method set), re-signed with a self-consistent digest, must be rejected.
func TestRegisterExternal_ReSignedInvalidDefinition_TRACEMethod(t *testing.T) {
	r := New()
	pkg := makePackage(t, "demo", 1, "do-thing", "s")

	// Make the content invalid: TRACE is a V1-rejected HTTP method.
	pkg.Actions[0].Binding.Method = "TRACE"

	// Re-sign: recompute a fresh digest over the now-invalid content so the
	// payload is internally self-consistent (VerifyDigest would pass).
	digest, err := spec.DefinitionDigest(pkg)
	require.NoError(t, err)
	pkg.Digest = digest
	pkg.Metadata.Digest = digest
	require.NoError(t, spec.VerifyDigest(pkg), "prelude: re-signed payload must be self-consistent")

	_, err = r.RegisterExternal(pkg)
	require.Error(t, err, "an invalid-Definition re-signed package must be rejected (full validation, not just digest)")
	assert.Contains(t, err.Error(), "TRACE", "full validation must reject the invalid method, not just re-verify the digest")
	assert.Equal(t, 0, r.Len(), "rejected payload must not be registered")
}

// Adversarial: a package whose endpoint.base_url is http (V1 requires https),
// re-signed, must be rejected by the full loader validation.
func TestRegisterExternal_ReSignedInvalidDefinition_HTTPSEndpoint(t *testing.T) {
	r := New()
	pkg := makePackage(t, "demo", 1, "do-thing", "s")
	pkg.Metadata.Endpoint.BaseURL = "http://insecure.example.com" // not https

	digest, err := spec.DefinitionDigest(pkg)
	require.NoError(t, err)
	pkg.Digest = digest
	pkg.Metadata.Digest = digest

	_, err = r.RegisterExternal(pkg)
	require.Error(t, err)
	assert.Equal(t, 0, r.Len())
}

// Adversarial: a package whose action has no input_schema (required), re-signed,
// must be rejected.
func TestRegisterExternal_ReSignedInvalidDefinition_MissingSchema(t *testing.T) {
	r := New()
	pkg := makePackage(t, "demo", 1, "do-thing", "s")
	pkg.Actions[0].Catalog.InputSchema = nil

	digest, err := spec.DefinitionDigest(pkg)
	require.NoError(t, err)
	pkg.Digest = digest
	pkg.Metadata.Digest = digest

	_, err = r.RegisterExternal(pkg)
	require.Error(t, err)
	assert.Equal(t, 0, r.Len())
}

// Tampering an Agent-visible field (summary) with the stale digest kept on BOTH
// fields must be rejected: VerifyDigest recomputes a different digest.
func TestRegisterExternal_TamperedSummaryRejected(t *testing.T) {
	r := New()
	pkg := makePackage(t, "demo", 1, "do-thing", "right-summary")
	require.NoError(t, spec.VerifyDigest(pkg))

	pkg.Actions[0].Catalog.Summary = "tampered-summary" // digest now stale

	_, err := r.RegisterExternal(pkg)
	require.Error(t, err, "tampered payload with a stale digest must be rejected (fail-closed)")
	assert.Equal(t, 0, r.Len(), "rejected payload must not be registered")
}

// Tampering the server-only HTTP binding (method) is equally caught: the binding
// is part of the canonical digest projection, AND full validation would reject
// an invalid method. Here we keep a VALID method (POST) so only the digest check
// fires.
func TestRegisterExternal_TamperedBindingRejected(t *testing.T) {
	r := New()
	pkg := makePackage(t, "demo", 1, "do-thing", "s")
	require.NoError(t, spec.VerifyDigest(pkg))

	pkg.Actions[0].Binding.Method = "POST" // was GET; still valid, but digest now stale

	_, err := r.RegisterExternal(pkg)
	require.Error(t, err)
	assert.Equal(t, 0, r.Len())
}

// A correct digest on both fields registers successfully (positive control).
func TestRegisterExternal_ValidPayloadRegisters(t *testing.T) {
	r := New()
	pkg := makePackage(t, "demo", 1, "do-thing", "s")
	_, err := r.RegisterExternal(pkg)
	require.NoError(t, err)
	got, ok := r.LookupByDigest(pkg.Digest)
	require.True(t, ok)
	assert.Equal(t, pkg.Digest, got.Definition.Digest)
}
