package app

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

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/provider"
)

type recordingConfigDB struct {
	db coredb.DB
	tx *recordingConfigTx
}

func (db *recordingConfigDB) QueryRow(ctx context.Context, query string, args ...any) coredb.Row {
	return db.db.QueryRow(ctx, query, args...)
}

func (db *recordingConfigDB) Query(ctx context.Context, query string, args ...any) (coredb.Rows, error) {
	return db.db.Query(ctx, query, args...)
}

func (db *recordingConfigDB) Exec(ctx context.Context, query string, args ...any) (coredb.Result, error) {
	return db.db.Exec(ctx, query, args...)
}

func (db *recordingConfigDB) BeginTx(ctx context.Context, options coredb.TxOptions) (coredb.Tx, error) {
	tx, err := db.db.BeginTx(ctx, options)
	if err != nil {
		return nil, err
	}
	db.tx = &recordingConfigTx{tx: tx}
	return db.tx, nil
}

type recordingConfigTx struct {
	tx          coredb.Tx
	execQueries []string
}

func (tx *recordingConfigTx) QueryRow(ctx context.Context, query string, args ...any) coredb.Row {
	return tx.tx.QueryRow(ctx, query, args...)
}

func (tx *recordingConfigTx) Query(ctx context.Context, query string, args ...any) (coredb.Rows, error) {
	return tx.tx.Query(ctx, query, args...)
}

func (tx *recordingConfigTx) Exec(ctx context.Context, query string, args ...any) (coredb.Result, error) {
	tx.execQueries = append(tx.execQueries, query)
	return tx.tx.Exec(ctx, query, args...)
}

func (tx *recordingConfigTx) Commit(ctx context.Context) error {
	return tx.tx.Commit(ctx)
}

func (tx *recordingConfigTx) Rollback(ctx context.Context) error {
	return tx.tx.Rollback(ctx)
}

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

	ctx := context.Background()
	pool := startAppRollbackDB(t, ctx)
	recordingDB := &recordingConfigDB{db: pool}
	now := time.Now().UTC()
	fixture := seedAppAdminFixture(t, pool, "github_config_portable", now)
	baseStore := New(pool, Options{AppCredentialStorageKey: testAppCredentialStorageKey()})
	requestAndApproveAppInstallationForTests(t, ctx, baseStore, fixture.UserID, fixture.UserID, fixture.WorkspaceID, "github", nil)
	appStore := New(recordingDB, Options{AppCredentialStorageKey: testAppCredentialStorageKey()})

	_, err := appStore.Provider().SaveGitHubAppConfigForWorkspaceAdmin(ctx, fixture.UserID, fixture.WorkspaceID, provider.UpsertGitHubAppConfigParams{
		AppID:         12345,
		AppSlug:       "agentteam-test",
		AppName:       "AgentTeam Test",
		HTMLURL:       "https://github.com/apps/agentteam-test",
		ClientID:      "Iv1.test",
		ClientSecret:  "client-secret-value",
		PrivateKeyPEM: "-----BEGIN RSA PRIVATE KEY-----\nkey\n-----END RSA PRIVATE KEY-----",
		WebhookSecret: "whsec_test",
		OwnerLogin:    "acme",
		OwnerID:       67890,
	})
	require.NoError(t, err)
	require.NotNil(t, recordingDB.tx)
	requirePortableConfigSaveQueries(t, recordingDB.tx.execQueries)
}

func requirePortableConfigSaveQueries(t *testing.T, queries []string) {
	t.Helper()
	require.NotEmpty(t, queries)
	for _, query := range queries {
		require.NotContains(t, strings.ToUpper(query), "LOCK TABLE")
		require.NotContains(t, strings.ToUpper(query), "IN EXCLUSIVE MODE")
	}
}
