package automation

import (
	"context"
	"strings"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	automationstore "github.com/tidbcloud/AgentTeam/internal/store/automation"
)

func TestAutomationSecretsEncryptAndAuthorize(t *testing.T) {
	ctx := context.Background()
	db, err := openServiceTestSQLiteDB(t)
	require.NoError(t, err)
	require.NoError(t, db.AutoMigrate(&automationstore.AutomationSecret{}))
	store := automationstore.New(db)
	now := time.Date(2026, 6, 14, 10, 0, 0, 0, time.UTC)
	svc := NewAutomationsService(store, func() time.Time { return now }, nil)
	svc.SetAutomationCredentialsKey([]byte("0123456789abcdef0123456789abcdef"))
	authorizer := &recordingAutomationSecretAuthorizer{}
	svc.SetAuthorizer(authorizer)

	secret, err := svc.UpsertAutomationSecret(ctx, "ws-1", "user-1", AutomationSecretMutation{
		RepositoryOwner: " pingcap ",
		RepositoryName:  " agentteam ",
		Name:            " deploy_token ",
		Value:           "plain-secret-token",
	})
	require.NoError(t, err)
	require.Equal(t, "deploy_token", secret.Name)
	require.Equal(t, "user-1", secret.UpdatedBy)
	require.Equal(t, []string{"pingcap/agentteam"}, authorizer.manageRepos)

	stored, err := store.GetAutomationSecret(ctx, "ws-1", "pingcap", "agentteam", "deploy_token")
	require.NoError(t, err)
	require.NotEmpty(t, stored.ValueCiphertext)
	require.NotEqual(t, "plain-secret-token", stored.ValueCiphertext)
	require.NotContains(t, stored.ValueCiphertext, "plain-secret-token")

	listed, err := svc.ListAutomationSecrets(ctx, "ws-1", "user-1", "pingcap", "agentteam", 1, 30)
	require.NoError(t, err)
	require.Len(t, listed.Secrets, 1)
	require.False(t, listed.HasMore)
	require.Equal(t, "deploy_token", listed.Secrets[0].Name)
	require.Equal(t, []string{"pingcap/agentteam"}, authorizer.readRepos)

	require.NoError(t, svc.DeleteAutomationSecret(ctx, "ws-1", "user-1", "pingcap", "agentteam", "deploy_token"))
	require.Equal(t, []string{"pingcap/agentteam", "pingcap/agentteam"}, authorizer.manageRepos)
}

func TestAutomationSecretUpsertRequiresConfiguredKey(t *testing.T) {
	ctx := context.Background()
	db, err := openServiceTestSQLiteDB(t)
	require.NoError(t, err)
	require.NoError(t, db.AutoMigrate(&automationstore.AutomationSecret{}))
	svc := NewAutomationsService(automationstore.New(db), time.Now, nil)

	_, err = svc.UpsertAutomationSecret(ctx, "ws-1", "user-1", AutomationSecretMutation{
		RepositoryOwner: "pingcap",
		RepositoryName:  "agentteam",
		Name:            "deploy_token",
		Value:           "plain-secret-token",
	})
	require.ErrorIs(t, err, ErrInvalidArgument)
	require.Contains(t, err.Error(), "storage is not configured")
}

func TestClaimAutomationAuthorizerSecretPermissionsAreSeparate(t *testing.T) {
	actor := AutomationActor{
		Subject:       "user-1",
		Authenticated: true,
		Claims: map[string]any{
			"workspace_ids":          []any{"ws-1"},
			"automation_permissions": []any{"automation:run:start"},
		},
	}
	request := AutomationAuthorizationRequest{Actor: actor, WorkspaceID: "ws-1", RepositoryOwner: "pingcap", RepositoryName: "agentteam"}
	authorizer := ClaimAutomationAuthorizer{}
	require.ErrorIs(t, authorizer.CanReadAutomationSecret(context.Background(), request), ErrForbidden)
	require.ErrorIs(t, authorizer.CanManageAutomationSecret(context.Background(), request), ErrForbidden)
	require.ErrorIs(t, authorizer.CanUseAutomationSecret(context.Background(), request), ErrForbidden)

	for permission, check := range map[string]func(context.Context, AutomationAuthorizationRequest) error{
		"automation:secret:read":   authorizer.CanReadAutomationSecret,
		"automation:secret:manage": authorizer.CanManageAutomationSecret,
		"automation:secret:use":    authorizer.CanUseAutomationSecret,
	} {
		request.Actor.Claims["automation_permissions"] = []any{permission}
		require.NoError(t, check(context.Background(), request), permission)
	}
}

type recordingAutomationSecretAuthorizer struct {
	AllowAutomationAuthorizer
	readRepos   []string
	manageRepos []string
	useRepos    []string
	denyUse     bool
}

func (a *recordingAutomationSecretAuthorizer) CanReadAutomationSecret(_ context.Context, request AutomationAuthorizationRequest) error {
	a.readRepos = append(a.readRepos, automationSecretRepoForTest(request))
	return nil
}

func (a *recordingAutomationSecretAuthorizer) CanManageAutomationSecret(_ context.Context, request AutomationAuthorizationRequest) error {
	a.manageRepos = append(a.manageRepos, automationSecretRepoForTest(request))
	return nil
}

func (a *recordingAutomationSecretAuthorizer) CanUseAutomationSecret(_ context.Context, request AutomationAuthorizationRequest) error {
	a.useRepos = append(a.useRepos, automationSecretRepoForTest(request))
	if a.denyUse {
		return forbidden("Automation secret use denied")
	}
	return nil
}

func automationSecretRepoForTest(request AutomationAuthorizationRequest) string {
	return strings.TrimSpace(request.RepositoryOwner) + "/" + strings.TrimSpace(request.RepositoryName)
}
