package automation

import (
	"context"
	"errors"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
	"gorm.io/gorm"
)

func TestAutomationSecretsUpsertListGetAndDelete(t *testing.T) {
	store := newAutomationStoreForTest(t)
	ctx := context.Background()
	createdAt := time.Date(2026, 6, 14, 10, 0, 0, 0, time.UTC)
	updatedAt := createdAt.Add(time.Hour)

	created, err := store.UpsertAutomationSecret(ctx, AutomationSecret{
		WorkspaceID:     " ws-1 ",
		RepositoryOwner: " pingcap ",
		RepositoryName:  " agentteam ",
		Name:            " deploy_token ",
		ValueCiphertext: " ciphertext-v1 ",
		CreatedBy:       " user-1 ",
		UpdatedBy:       " user-1 ",
		CreatedAt:       createdAt,
		UpdatedAt:       createdAt,
	})
	require.NoError(t, err)
	require.Equal(t, "ws-1", created.WorkspaceID)
	require.Equal(t, "pingcap", created.RepositoryOwner)
	require.Equal(t, "agentteam", created.RepositoryName)
	require.Equal(t, "deploy_token", created.Name)
	require.Equal(t, "ciphertext-v1", created.ValueCiphertext)
	require.Equal(t, "user-1", created.CreatedBy)
	require.Equal(t, "user-1", created.UpdatedBy)
	require.Equal(t, createdAt, created.CreatedAt)
	require.Equal(t, createdAt, created.UpdatedAt)

	updated, err := store.UpsertAutomationSecret(ctx, AutomationSecret{
		WorkspaceID:     "ws-1",
		RepositoryOwner: "pingcap",
		RepositoryName:  "agentteam",
		Name:            "deploy_token",
		ValueCiphertext: "ciphertext-v2",
		CreatedBy:       "user-ignored",
		UpdatedBy:       "user-2",
		CreatedAt:       updatedAt,
		UpdatedAt:       updatedAt,
	})
	require.NoError(t, err)
	require.Equal(t, "ciphertext-v2", updated.ValueCiphertext)
	require.Equal(t, "user-1", updated.CreatedBy)
	require.Equal(t, "user-2", updated.UpdatedBy)
	require.Equal(t, createdAt, updated.CreatedAt)
	require.Equal(t, updatedAt, updated.UpdatedAt)

	_, err = store.UpsertAutomationSecret(ctx, AutomationSecret{
		WorkspaceID:     "ws-1",
		RepositoryOwner: "pingcap",
		RepositoryName:  "other",
		Name:            "deploy_token",
		ValueCiphertext: "other-repo-ciphertext",
		CreatedBy:       "user-1",
		UpdatedBy:       "user-1",
		CreatedAt:       createdAt,
		UpdatedAt:       createdAt,
	})
	require.NoError(t, err)

	result, err := store.ListAutomationSecrets(ctx, "ws-1", "pingcap", "agentteam", 1, 30)
	require.NoError(t, err)
	secrets := result.Secrets
	require.Len(t, secrets, 1)
	require.Equal(t, "deploy_token", secrets[0].Name)
	require.Empty(t, secrets[0].ValueCiphertext)

	loaded, err := store.GetAutomationSecret(ctx, "ws-1", "pingcap", "agentteam", "deploy_token")
	require.NoError(t, err)
	require.Equal(t, updated, loaded)

	require.NoError(t, store.DeleteAutomationSecret(ctx, "ws-1", "pingcap", "agentteam", "deploy_token"))
	_, err = store.GetAutomationSecret(ctx, "ws-1", "pingcap", "agentteam", "deploy_token")
	require.ErrorIs(t, err, gorm.ErrRecordNotFound)
	err = store.DeleteAutomationSecret(ctx, "ws-1", "pingcap", "agentteam", "deploy_token")
	require.True(t, errors.Is(err, gorm.ErrRecordNotFound), "DeleteAutomationSecret error = %v", err)
}

func TestListAutomationSecretsIsMetadataOnlyAndPaginated(t *testing.T) {
	store := newAutomationStoreForTest(t)
	ctx := context.Background()
	now := time.Date(2026, 6, 14, 10, 30, 0, 0, time.UTC)
	for _, secret := range []AutomationSecret{
		{WorkspaceID: "ws-1", RepositoryOwner: "pingcap", RepositoryName: "agentteam", Name: "alpha", ValueCiphertext: "ciphertext-alpha", CreatedAt: now, UpdatedAt: now},
		{WorkspaceID: "ws-1", RepositoryOwner: "pingcap", RepositoryName: "agentteam", Name: "beta", ValueCiphertext: "ciphertext-beta", CreatedAt: now, UpdatedAt: now},
		{WorkspaceID: "ws-1", RepositoryOwner: "pingcap", RepositoryName: "agentteam", Name: "gamma", ValueCiphertext: "ciphertext-gamma", CreatedAt: now, UpdatedAt: now},
	} {
		_, err := store.UpsertAutomationSecret(ctx, secret)
		require.NoError(t, err)
	}

	pageOne, err := store.ListAutomationSecrets(ctx, "ws-1", "pingcap", "agentteam", 1, 2)
	require.NoError(t, err)
	require.True(t, pageOne.HasMore)
	require.Equal(t, []string{"alpha", "beta"}, automationSecretNamesForTest(pageOne.Secrets))
	for _, secret := range pageOne.Secrets {
		require.Empty(t, secret.ValueCiphertext)
	}

	pageTwo, err := store.ListAutomationSecrets(ctx, "ws-1", "pingcap", "agentteam", 2, 2)
	require.NoError(t, err)
	require.False(t, pageTwo.HasMore)
	require.Equal(t, []string{"gamma"}, automationSecretNamesForTest(pageTwo.Secrets))
}

func TestGetAutomationSecretCiphertextsByNamesIsExplicitAndRepoScoped(t *testing.T) {
	store := newAutomationStoreForTest(t)
	ctx := context.Background()
	now := time.Date(2026, 6, 14, 11, 0, 0, 0, time.UTC)
	seedAutomationSecretScopeFixture(t, ctx, store, now)

	byName, err := store.GetAutomationSecretCiphertextsByNames(ctx, "ws-1", "pingcap", "agentteam", []string{" alpha ", "missing", "alpha", "", "beta"})
	require.NoError(t, err)
	require.Equal(t, map[string]string{"alpha": "ciphertext-alpha", "beta": "ciphertext-beta"}, byName)
	require.NotContains(t, byName, "missing")

	empty, err := store.GetAutomationSecretCiphertextsByNames(ctx, "ws-1", "pingcap", "agentteam", nil)
	require.NoError(t, err)
	require.Empty(t, empty)
}

func TestGetExistingAutomationSecretNamesIsExplicitAndRepoScoped(t *testing.T) {
	store := newAutomationStoreForTest(t)
	ctx := context.Background()
	now := time.Date(2026, 6, 14, 11, 30, 0, 0, time.UTC)
	seedAutomationSecretScopeFixture(t, ctx, store, now)

	existing, err := store.GetExistingAutomationSecretNames(ctx, "ws-1", "pingcap", "agentteam", []string{" alpha ", "missing", "alpha", "", "beta"})
	require.NoError(t, err)
	require.Equal(t, map[string]struct{}{"alpha": {}, "beta": {}}, existing)

	empty, err := store.GetExistingAutomationSecretNames(ctx, "ws-1", "pingcap", "agentteam", nil)
	require.NoError(t, err)
	require.Empty(t, empty)
}

func seedAutomationSecretScopeFixture(t *testing.T, ctx context.Context, store *Store, now time.Time) {
	t.Helper()
	for _, secret := range []AutomationSecret{
		{WorkspaceID: "ws-1", RepositoryOwner: "pingcap", RepositoryName: "agentteam", Name: "alpha", ValueCiphertext: "ciphertext-alpha", CreatedAt: now, UpdatedAt: now},
		{WorkspaceID: "ws-1", RepositoryOwner: "pingcap", RepositoryName: "agentteam", Name: "beta", ValueCiphertext: "ciphertext-beta", CreatedAt: now, UpdatedAt: now},
		{WorkspaceID: "ws-1", RepositoryOwner: "pingcap", RepositoryName: "other", Name: "alpha", ValueCiphertext: "other-repo-ciphertext", CreatedAt: now, UpdatedAt: now},
		{WorkspaceID: "ws-2", RepositoryOwner: "pingcap", RepositoryName: "agentteam", Name: "alpha", ValueCiphertext: "other-workspace-ciphertext", CreatedAt: now, UpdatedAt: now},
	} {
		_, err := store.UpsertAutomationSecret(ctx, secret)
		require.NoError(t, err)
	}
}

func automationSecretNamesForTest(secrets []AutomationSecret) []string {
	names := make([]string, 0, len(secrets))
	for _, secret := range secrets {
		names = append(names, secret.Name)
	}
	return names
}
