package extension

import (
	"context"
	"os"
	"testing"
	"time"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/coredb/testkit"
)

var extensionStoreTiDB testkit.TiDBCoreDBFixture

func TestMain(m *testing.M) {
	os.Exit(testkit.RunTestsWithTiDBCoreDBFixture(m, "extension_store", &extensionStoreTiDB))
}

// startRollbackDB returns an isolated, fully-migrated TiDB database whose
// changes are rolled back at the end of the test. The shared Service Actor
// substrate tables back every assertion in this package.
func startRollbackDB(t *testing.T, ctx context.Context) coredb.DB {
	t.Helper()
	return extensionStoreTiDB.RollbackDB(t, ctx)
}

// extensionStoreFixture holds the durable foreign-key rows an Extension
// installation/connection/authorization requires: an organization, workspace,
// and a human member that attributes the install/connect/grant actions. It
// mirrors the seeding used by the Service Actor integration tests.
type extensionStoreFixture struct {
	OrganizationID string
	UserID         string
	WorkspaceID    string
	HumanMemberID  string
}

func seedExtensionStoreFixture(t testing.TB, db coredb.QueryExecer, suffix string, now time.Time) extensionStoreFixture {
	t.Helper()
	fixture := extensionStoreFixture{
		OrganizationID: "org_ext_" + suffix,
		UserID:         "usr_ext_" + suffix,
		WorkspaceID:    "wsp_ext_" + suffix,
		HumanMemberID:  "mem_ext_human_" + suffix,
	}
	mustExec(t, db, `
INSERT INTO users (id, email, name, display_name, password_hash, created_at, updated_at)
VALUES ($1, $2, $3, $3, 'hash', $4, $4)
`, fixture.UserID, suffix+"@example.com", suffix, now)
	mustExec(t, db, `
INSERT INTO organizations (id, slug, name, created_by_user_id, created_at, updated_at)
VALUES ($1, $2, $2, $3, $4, $4)
`, fixture.OrganizationID, suffix, fixture.UserID, now)
	mustExec(t, db, `
INSERT INTO workspaces (id, organization_id, slug, name, created_at, updated_at)
VALUES ($1, $2, $3, $3, $4, $4)
`, fixture.WorkspaceID, fixture.OrganizationID, suffix, now)
	mustExec(t, db, `
INSERT INTO members (id, workspace_id, type, display_name, user_id, workspace_role, status, created_at, updated_at)
VALUES ($1, $2, 'human', 'Human', $3, 'owner', 'active', $4, $4)
`, fixture.HumanMemberID, fixture.WorkspaceID, fixture.UserID, now)
	return fixture
}

func mustExec(t testing.TB, execer coredb.QueryExecer, query string, args ...any) {
	t.Helper()
	_, err := execer.Exec(context.Background(), query, args...)
	require.NoError(t, err)
}

// seedExtensionStoreAgent seeds an active Agent principal (member + machine +
// agent row) in the workspace so agent_extension_catalogs rows satisfy the agent
// foreign key.
func seedExtensionStoreAgent(t testing.TB, db coredb.QueryExecer, workspaceID, userID, agentID string, now time.Time) {
	t.Helper()
	memberID := "mem_ext_agent_" + agentID
	machineID := "mach_ext_agent_" + agentID
	mustExec(t, db, `
INSERT INTO members (id, workspace_id, type, display_name, status, created_at, updated_at)
VALUES ($1, $2, 'agent', $3, 'active', $4, $4)
`, memberID, workspaceID, agentID, now)
	mustExec(t, db, `
INSERT INTO machines (id, workspace_id, created_by_user_id, name, api_key, status, connected_at, disconnected_at, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, 'active', $6, NULL, $6, $6)
`, machineID, workspaceID, userID, agentID, "api_key_"+agentID, now)
	mustExec(t, db, `
INSERT INTO agents (id, workspace_id, machine_id, member_id, name, runtime, model, description, status, activity, activity_detail, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, 'claude', 'claude', '', 'active', 'active', '', $6, $6)
`, agentID, workspaceID, machineID, memberID, agentID, now)
}
