package extensionflow

import (
	"context"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/extension/registry"
	"github.com/tidbcloud/AgentTeam/internal/store/extension"
	"github.com/tidbcloud/AgentTeam/internal/store/serviceactor"
	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
)

func serviceactorInstallation(id, installationID string) serviceactor.InstallationExtension {
	return serviceactor.InstallationExtension{
		ID:                    id,
		ServiceInstallationID: installationID,
	}
}

// TestReauthorizeBuiltinRequiresBoundRegistry proves the seam fails closed
// before any resolution when the authoritative registry is unavailable.
func TestReauthorizeBuiltinRequiresBoundRegistry(t *testing.T) {

	service := New(nil, nil, nil, Options{})
	err := service.ReauthorizeBuiltin(context.Background(), BuiltinReauthorization{
		WorkspaceID:      "wsp_1",
		AgentID:          "agt_1",
		AgentMemberID:    "mem_1",
		DefinitionDigest: "sha256:" + "a",
	})
	require.Error(t, err)
}

func TestCompareResolvedIdentityClassifiesEveryMismatchForbidden(t *testing.T) {

	base := invocationResolution{
		selection: serviceactorInstallation("sel_1", "inst_1"),
		definition: registry.RegisteredExtension{
			Definition: registry.Definition{
				Domain:  "mail",
				Version: 1,
				Digest:  "sha256:abc",
			},
		},
		action:               registry.DefinitionAction{Name: "send-draft"},
		connection:           extension.RuntimeConnection{ID: "conn_1"},
		connectionGeneration: "gen_9",
		authorizedByMemberID: "mem_authorizer",
		catalogVersion:       7,
	}
	matching := BuiltinReauthorization{
		ServiceInstallationExtensionID: "sel_1",
		ServiceInstallationID:          "inst_1",
		AuthorizedByMemberID:           "mem_authorizer",
		Action:                         "send-draft",
		DefinitionVersion:              1,
		DefinitionDigest:               "sha256:abc",
		CatalogVersion:                 7,
		ServiceConnectionID:            "conn_1",
		ServiceConnectionGeneration:    "gen_9",
	}
	require.NoError(t, compareResolvedIdentity(base, matching))

	mismatchedFacets := map[string]BuiltinReauthorization{
		"selection extension": {
			ServiceInstallationExtensionID: "sel_other",
			ServiceInstallationID:          "inst_1",
			AuthorizedByMemberID:           "mem_authorizer",
			Action:                         "send-draft",
			DefinitionVersion:              1,
			DefinitionDigest:               "sha256:abc",
			ServiceConnectionID:            "conn_1",
			ServiceConnectionGeneration:    "gen_9",
		},
		"service installation": {
			ServiceInstallationExtensionID: "sel_1",
			ServiceInstallationID:          "inst_other",
			AuthorizedByMemberID:           "mem_authorizer",
			Action:                         "send-draft",
			DefinitionVersion:              1,
			DefinitionDigest:               "sha256:abc",
			ServiceConnectionID:            "conn_1",
			ServiceConnectionGeneration:    "gen_9",
		},
		"authorizer": {
			ServiceInstallationExtensionID: "sel_1",
			ServiceInstallationID:          "inst_1",
			AuthorizedByMemberID:           "mem_changed",
			Action:                         "send-draft",
			DefinitionVersion:              1,
			DefinitionDigest:               "sha256:abc",
			ServiceConnectionID:            "conn_1",
			ServiceConnectionGeneration:    "gen_9",
		},
		"action": {
			ServiceInstallationExtensionID: "sel_1",
			ServiceInstallationID:          "inst_1",
			AuthorizedByMemberID:           "mem_authorizer",
			Action:                         "search-messages",
			DefinitionVersion:              1,
			DefinitionDigest:               "sha256:abc",
			ServiceConnectionID:            "conn_1",
			ServiceConnectionGeneration:    "gen_9",
		},
		"definition version": {
			ServiceInstallationExtensionID: "sel_1",
			ServiceInstallationID:          "inst_1",
			AuthorizedByMemberID:           "mem_authorizer",
			Action:                         "send-draft",
			DefinitionVersion:              2,
			DefinitionDigest:               "sha256:abc",
			ServiceConnectionID:            "conn_1",
			ServiceConnectionGeneration:    "gen_9",
		},
		"definition digest": {
			ServiceInstallationExtensionID: "sel_1",
			ServiceInstallationID:          "inst_1",
			AuthorizedByMemberID:           "mem_authorizer",
			Action:                         "send-draft",
			DefinitionVersion:              1,
			DefinitionDigest:               "sha256:def",
			ServiceConnectionID:            "conn_1",
			ServiceConnectionGeneration:    "gen_9",
		},
		"connection": {
			ServiceInstallationExtensionID: "sel_1",
			ServiceInstallationID:          "inst_1",
			AuthorizedByMemberID:           "mem_authorizer",
			Action:                         "send-draft",
			DefinitionVersion:              1,
			DefinitionDigest:               "sha256:abc",
			ServiceConnectionID:            "conn_other",
			ServiceConnectionGeneration:    "gen_9",
		},
		"connection generation": {
			ServiceInstallationExtensionID: "sel_1",
			ServiceInstallationID:          "inst_1",
			AuthorizedByMemberID:           "mem_authorizer",
			Action:                         "send-draft",
			DefinitionVersion:              1,
			DefinitionDigest:               "sha256:abc",
			ServiceConnectionID:            "conn_1",
			ServiceConnectionGeneration:    "gen_rotated",
		},
	}
	for facet, envelope := range mismatchedFacets {
		envelope.CatalogVersion = matching.CatalogVersion
		mismatchedFacets[facet] = envelope
	}
	catalogVersionMismatch := matching
	catalogVersionMismatch.CatalogVersion++
	mismatchedFacets["catalog version"] = catalogVersionMismatch
	for facet, envelope := range mismatchedFacets {
		require.ErrorIsf(
			t,
			compareResolvedIdentity(base, envelope),
			storeerr.ErrForbidden,
			"%s mismatch must classify as forbidden, not upstream",
			facet,
		)
	}
}
