package app

import (
	"context"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/app/installation"
	"github.com/tidbcloud/AgentTeam/internal/store/serviceactor"
)

func TestCapabilityPolicyCanDisableSubscriptionRequirement(t *testing.T) {
	t.Parallel()

	config := []byte(`{
		"tools":["list-items","create-item"],
		"scopes":["items.read","items.write"],
		"requiresSubscriptions":false
	}`)
	capability := agentAppCapabilitySetForService(
		"github",
		true,
		false,
		config,
	)
	require.True(t, capability.Supported)
	require.Equal(t, "github", capability.MCPName)
	require.Equal(t,
		[]string{"create-item", "list-items"},
		capability.Tools,
	)
	require.Equal(t,
		[]string{"items.read", "items.write"},
		capability.Scopes,
	)
	require.False(t,
		agentAppCapabilitySetForService(
			"gitea",
			true,
			false,
			[]byte(`{"tools":["list"],"scopes":["read"]}`),
		).Supported,
		"capabilities without an explicit subscription requirement remain unsupported",
	)
}

func TestCapabilityPolicyCanRequireExplicitAuthorization(t *testing.T) {
	t.Parallel()

	row := agentAppAuthorizationPolicyRow{
		AgentID:              "agt_feature",
		AgentMemberID:        "mem_agent_feature",
		AgentOwnerMemberID:   "mem_owner",
		AppInstallationID:    "appinst_feature",
		AppID:                "app_github",
		AppSlug:              "github",
		WorkspaceID:          "wsp_feature",
		AppMemberID:          "mem_app_feature",
		InstallationEnabled:  true,
		HasEnabledConnection: true,
		HasMCPTools:          true,
		MCPCapabilityConfig: []byte(`{
			"tools":["list-items"],
			"scopes":["items.read"],
			"authorizationMode":"explicit_only",
			"requiresSubscriptions":false
		}`),
	}
	_, err := row.authorizationRecord([]string{"items.read"})
	require.ErrorContains(t, err, "app_not_authorized_for_agent")

	row.AuthorizationID = "spa_feature"
	row.Status = AgentAppAuthorizationStatusActive
	row.Scopes = []string{"items.read"}
	row.AuthorizedByMemberID = "mem_owner"
	row.PolicyVersion = 1
	record, err := row.authorizationRecord([]string{"items.read"})
	require.NoError(t, err)
	require.Equal(t, "spa_feature", record.ID)
	require.Equal(t, []string{"items.read"}, record.Scopes)
}

func TestSyncAppServiceCapabilitiesWritesAppNotificationCapabilities(t *testing.T) {
	t.Parallel()

	ctx := context.Background()
	pool := startAppRollbackDB(t, ctx)
	store := serviceactor.New(pool)
	now := time.Now().UTC()
	manifestJSON := []byte(`{
		"schema_version":"1",
		"slug":"approval-app",
		"version":"1.0.0",
		"capabilities":{"runtime":{
			"events":["agentteam.app.notification.action"],
			"scopes":["messages.write","app.notifications.write","app.notification_actions.read"],
			"notifications":{"targets":["human_dm","bound_scope"],"content":["message","interactive_card"]}
		}}
	}`)

	err := coredb.WithTx(ctx, pool, func(tx coredb.Tx) error {
		txStore := store.InTx(tx)
		definition, err := txStore.UpsertDefinition(ctx, serviceactor.DefinitionUpsert{
			ID: "svcdef_bot_notifications", ServiceKind: serviceactor.KindApp,
			Slug: "approval-app", Name: "Approval", LatestVersion: "1.0.0",
			Manifest: manifestJSON, Status: serviceactor.StatusActive, Now: now,
		})
		if err != nil {
			return err
		}
		return installation.SyncDefinitionCapabilities(ctx, txStore, definition, manifestJSON, now)
	})
	require.NoError(t, err)

	capabilities, err := store.ListCapabilities(ctx, "svcdef_bot_notifications")
	require.NoError(t, err)
	byKey := make(map[string]serviceactor.Capability, len(capabilities))
	for _, capability := range capabilities {
		byKey[capability.CapabilityKey] = capability
	}
	require.Contains(t, byKey, serviceactor.CapabilityMessageWrite)
	require.Contains(t, byKey, serviceactor.CapabilityAppNotificationsWrite)
	require.Contains(t, byKey, serviceactor.CapabilityAppNotificationActionsRead)
	require.JSONEq(t, `{
		"events":["agentteam.app.notification.action"],
		"scopes":["app.notification_actions.read","app.notifications.write","messages.write"],
		"notifications":{"supported":true,"targets":["human_dm","bound_scope"],"content":["message","interactive_card"]}
	}`, string(byKey[serviceactor.CapabilityApp].Config))
}
