package agent

import (
	"context"
	"errors"
	"fmt"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/core/secrets"
	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/access"
	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
)

var (
	// ErrUnauthorized means the caller token is invalid.
	ErrUnauthorized = storeerr.ErrUnauthorized
	// ErrNotFound means the requested runtime object does not exist.
	ErrNotFound = storeerr.ErrNotFound
	// ErrPermissionModeCapabilityRequired means the target daemon must advertise
	// permission-mode support before a workspace-write start token can be issued.
	ErrPermissionModeCapabilityRequired = errors.New("agent permission mode capability required")
	// ErrPermissionModeStartRequired means workspace-write agents must receive
	// fresh tokens through a start or restart command, not daemon HTTP refresh.
	ErrPermissionModeStartRequired = errors.New("agent workspace-write token refresh requires restart")
)

// AuthenticatedAgent identifies an agent actor resolved from an agent bearer token.
type AuthenticatedAgent struct {
	AgentID       string
	WorkspaceID   string
	MemberID      string
	MachineID     string
	DaemonVersion string
}

// PreparedAgentStart is the core runtime state needed to build one daemon `agent:start` payload.
type PreparedAgentStart struct {
	AgentID                     string
	OrganizationID              string
	WorkspaceID                 string
	MachineID                   string
	MemberID                    string
	Name                        string
	DisplayName                 string
	Description                 string
	Runtime                     string
	PermissionMode              string
	RuntimePolicy               RuntimePolicySnapshot
	VisibleReplyContractEnabled bool
	RuntimeDebugEnabled         bool
	Model                       string
	ReasoningEffort             string
	LLMMode                     string
	BaseURL                     string
	APIKey                      string
	Headers                     map[string]string
	WireAPI                     string
	SessionID                   string
	AuthToken                   string
}

type preparedAgentStartRow struct {
	Prepared         PreparedAgentStart
	MemberID         string
	LLMMode          string
	BaseURL          string
	APIKeyCiphertext string
	HeadersJSON      []byte
	WireAPI          string
}

// MachineIdentity is the database identity of an authenticated daemon machine.
type MachineIdentity struct {
	MachineID       string
	WorkspaceID     string
	CreatedByUserID string
}

// ReadyPayload is the daemon `ready` message.
type ReadyPayload struct {
	Runtimes        []string
	RuntimeDefaults map[string]RuntimeDefaults
	RunningAgents   []string
	Hostname        string
	OS              string
	DaemonVersion   string
}

// RuntimeDefaults captures the concrete default settings currently reported by
// a machine runtime.
type RuntimeDefaults struct {
	Model           string
	ReasoningEffort string
}

// Options wires cross-domain dependencies needed by the agent runtime domain.
type Options struct {
	CredentialStorageKey        []byte
	LegacyCredentialStorageKeys [][]byte
}

// Service owns the core runtime auth/start/disconnect primitives.
type Service struct {
	db                          coredb.DB
	options                     Options
	credentialStorageKey        []byte
	legacyCredentialStorageKeys [][]byte
}

// New constructs a runtime Service.
func New(db coredb.DB) *Service {
	return NewWithOptions(db, Options{})
}

// NewWithOptions constructs a runtime Service with explicit cross-domain dependencies.
func NewWithOptions(db coredb.DB, options Options) *Service {
	return &Service{
		db:                          db,
		options:                     options,
		credentialStorageKey:        append([]byte(nil), options.CredentialStorageKey...),
		legacyCredentialStorageKeys: cloneCredentialStorageKeys(options.LegacyCredentialStorageKeys),
	}
}

func (service *Service) AuthenticateAgent(ctx context.Context, agentID string, bearerToken string) (AuthenticatedAgent, error) {
	trimmedAgentID := strings.TrimSpace(agentID)
	trimmedToken := strings.TrimSpace(bearerToken)
	if trimmedAgentID == "" || trimmedToken == "" {
		return AuthenticatedAgent{}, ErrUnauthorized
	}

	row := service.db.QueryRow(ctx, `
SELECT
    a.workspace_id,
    a.member_id,
    a.machine_id,
    machines.daemon_version,
    a.auth_token_hash
FROM agents a
JOIN members m ON m.id = a.member_id AND m.workspace_id = a.workspace_id AND m.type = 'agent'
JOIN machines ON machines.id = a.machine_id AND machines.workspace_id = a.workspace_id
JOIN workspaces w ON w.id = a.workspace_id
WHERE a.id = $1
  AND a.status <> 'archived'
  AND machines.status = 'active'
`, trimmedAgentID)

	var workspaceID string
	var memberID string
	var machineID string
	var daemonVersion string
	var tokenHash *string
	if err := row.Scan(&workspaceID, &memberID, &machineID, &daemonVersion, &tokenHash); err != nil {
		if coredb.IsNotFound(err) {
			return AuthenticatedAgent{}, ErrUnauthorized
		}
		return AuthenticatedAgent{}, fmt.Errorf("query agent auth: %w", err)
	}

	trimmedWorkspaceID := strings.TrimSpace(workspaceID)
	if trimmedWorkspaceID == "" {
		return AuthenticatedAgent{}, fmt.Errorf("invalid workspace id")
	}

	trimmedMemberID := strings.TrimSpace(memberID)
	if trimmedMemberID == "" {
		return AuthenticatedAgent{}, fmt.Errorf("invalid agent member id")
	}

	trimmedMachineID := strings.TrimSpace(machineID)
	if trimmedMachineID == "" {
		return AuthenticatedAgent{}, fmt.Errorf("invalid machine id")
	}

	trimmedTokenHash := strings.TrimSpace(valueOrEmpty(tokenHash))
	if trimmedTokenHash == "" {
		return AuthenticatedAgent{}, ErrUnauthorized
	}

	if !secrets.TokenMatchesHash(trimmedToken, trimmedTokenHash) {
		return AuthenticatedAgent{}, ErrUnauthorized
	}

	authenticated := AuthenticatedAgent{
		AgentID:       trimmedAgentID,
		WorkspaceID:   trimmedWorkspaceID,
		MemberID:      trimmedMemberID,
		MachineID:     trimmedMachineID,
		DaemonVersion: strings.TrimSpace(daemonVersion),
	}
	if _, err := access.DecideAgentSelfAuthorization(access.AgentSelf{
		AgentID:     authenticated.AgentID,
		WorkspaceID: authenticated.WorkspaceID,
		MemberID:    authenticated.MemberID,
	}, access.NewAgentSelfAuthorizationRequest(authenticated.AgentID, authenticated.WorkspaceID, authenticated.MemberID)); err != nil {
		if errors.Is(err, access.ErrForbidden) {
			return AuthenticatedAgent{}, ErrUnauthorized
		}
		return AuthenticatedAgent{}, fmt.Errorf("authorize agent self: %w", err)
	}

	return authenticated, nil
}

func valueOrEmpty(value *string) string {
	if value == nil {
		return ""
	}
	return *value
}

func (service *Service) AuthenticateMachine(ctx context.Context, apiKey string) (MachineIdentity, error) {
	trimmedAPIKey := strings.TrimSpace(apiKey)
	if trimmedAPIKey == "" {
		return MachineIdentity{}, ErrUnauthorized
	}

	row := service.db.QueryRow(ctx, `SELECT id, workspace_id, created_by_user_id FROM machines WHERE api_key = $1 AND status = 'active'`, trimmedAPIKey)

	var identity MachineIdentity
	if err := row.Scan(&identity.MachineID, &identity.WorkspaceID, &identity.CreatedByUserID); err != nil {
		if coredb.IsNotFound(err) {
			return MachineIdentity{}, ErrUnauthorized
		}
		return MachineIdentity{}, fmt.Errorf("query machine by api key: %w", err)
	}

	if _, err := access.DecideMachineSelfAuthorization(access.MachineSelf{
		MachineID:   identity.MachineID,
		WorkspaceID: identity.WorkspaceID,
	}, access.NewMachineSelfAuthorizationRequest(identity.MachineID, identity.WorkspaceID)); err != nil {
		if errors.Is(err, access.ErrForbidden) {
			return MachineIdentity{}, ErrUnauthorized
		}
		return MachineIdentity{}, fmt.Errorf("authorize machine self: %w", err)
	}

	return identity, nil
}

func (service *Service) MarkMachineReady(ctx context.Context, identity MachineIdentity, payload ReadyPayload) error {
	commandTag, err := service.db.Exec(ctx, `
UPDATE machines
SET hostname = $2,
    os = $3,
    daemon_version = $4,
    updated_at = NOW()
WHERE id = $1
  AND status = 'active'
  AND (
      COALESCE(hostname, '') <> $2 OR
      COALESCE(os, '') <> $3 OR
      COALESCE(daemon_version, '') <> $4
  )
`, identity.MachineID, payload.Hostname, payload.OS, payload.DaemonVersion)
	if err != nil {
		return fmt.Errorf("update machine ready metadata: %w", err)
	}
	if commandTag.RowsAffected() > 0 {
		return nil
	}
	active, err := machineActive(ctx, service.db, identity.MachineID)
	if err != nil {
		return err
	}
	if !active {
		return ErrUnauthorized
	}
	return nil
}

func (service *Service) MarkMachineDisconnected(ctx context.Context, machineID string) error {
	return nil
}

func machineActive(ctx context.Context, queryer coredb.QueryRower, machineID string) (bool, error) {
	var exists int
	err := queryer.QueryRow(ctx, `
SELECT 1
FROM machines
WHERE id = $1
  AND status = 'active'
`, strings.TrimSpace(machineID)).Scan(&exists)
	if err != nil {
		if coredb.IsNotFound(err) {
			return false, nil
		}
		return false, fmt.Errorf("check machine active: %w", err)
	}
	return true, nil
}

// ListAgentsForMachine returns all agents assigned to the given machine.
func (service *Service) ListAgentsForMachine(ctx context.Context, machineID string) ([]MachineAgent, error) {
	rows, err := service.db.Query(ctx, `
SELECT a.id, a.name, m.display_name, a.description, a.runtime, a.permission_mode, a.model, a.reasoning_effort,
       a.llm_mode, a.llm_base_url, a.llm_api_key_ciphertext, a.llm_headers_json, a.llm_wire_api,
       'inactive', 'offline',
       a.runtime_policy_generation,
       a.visible_reply_contract_enabled, COALESCE(prefs.runtime_debug_enabled, FALSE)
FROM agents a
JOIN members m ON m.id = a.member_id
JOIN machines mach ON mach.id = a.machine_id
JOIN users ON users.id = mach.created_by_user_id
LEFT JOIN user_preferences prefs ON prefs.user_id = users.id
WHERE a.machine_id = $1
  AND a.status <> 'archived'
ORDER BY a.name ASC
`, machineID)
	if err != nil {
		return nil, fmt.Errorf("list agents for machine: %w", err)
	}
	defer rows.Close()

	agents := make([]MachineAgent, 0)
	for rows.Next() {
		var ag MachineAgent
		var llmMode string
		var baseURL string
		var apiKeyCiphertext string
		var headersJSON []byte
		var wireAPI string
		var runtimePolicyGeneration int64
		var visibleReplyContractEnabled bool
		var runtimeDebugEnabled bool
		if err := rows.Scan(
			&ag.ID, &ag.Name, &ag.DisplayName, &ag.Description,
			&ag.Runtime, &ag.PermissionMode, &ag.Model, &ag.ReasoningEffort,
			&llmMode, &baseURL, &apiKeyCiphertext, &headersJSON, &wireAPI,
			&ag.Status, &ag.Activity,
			&runtimePolicyGeneration, &visibleReplyContractEnabled, &runtimeDebugEnabled,
		); err != nil {
			return nil, fmt.Errorf("scan agent: %w", err)
		}
		ag.VisibleReplyContractEnabled = visibleReplyContractEnabled
		ag.RuntimeDebugEnabled = runtimeDebugEnabled
		ag.PermissionMode = DefaultAgentPermissionMode(ag.PermissionMode)
		ag.RuntimePolicy = NewRuntimePolicySnapshot(ag.Runtime, ag.PermissionMode, runtimePolicyGeneration, ag.VisibleReplyContractEnabled)
		ag.ReasoningEffort = NormalizeReasoningEffortForRuntime(ag.Runtime, ag.ReasoningEffort)
		decodedLLM, err := DecodeStoredAgentLLMColumnsWithFallback(service.credentialStorageKey, service.legacyCredentialStorageKeys, llmMode, baseURL, apiKeyCiphertext, headersJSON, wireAPI)
		if err != nil {
			return nil, fmt.Errorf("decode agent llm: %w", err)
		}
		ag.LLMMode, ag.BaseURL, ag.APIKey, ag.Headers, ag.WireAPI = AgentLLMFieldsFromStored(decodedLLM)
		agents = append(agents, ag)
	}
	return agents, rows.Err()
}

func (service *Service) MarkMachinesDisconnectedOnStartup(ctx context.Context) (int64, error) {
	return 0, nil
}

func (service *Service) MarkMachinesDisconnectedOnStartupForWorkspaces(ctx context.Context, workspaceIDs []string) (int64, error) {
	return 0, nil
}

// UpdateAgentStatusFromMachine accepts agent status telemetry only when the agent belongs to the machine.
func (service *Service) UpdateAgentStatusFromMachine(ctx context.Context, machineID string, agentID string, status string) (bool, error) {
	return service.AgentBelongsToMachine(ctx, machineID, agentID)
}

// UpdateAgentActivityFromMachine accepts agent activity telemetry only when the agent belongs to the machine.
func (service *Service) UpdateAgentActivityFromMachine(ctx context.Context, machineID string, agentID string, activity string, detail string) (bool, error) {
	return service.AgentBelongsToMachine(ctx, machineID, agentID)
}

// UpdateAgentSessionFromMachine accepts agent session telemetry only when the
// agent belongs to the machine. Legacy daemons depend on the server-provided
// start config session mirror, so they still get a sparse DB update until they
// advertise local session resume support.
func (service *Service) UpdateAgentSessionFromMachine(ctx context.Context, machineID string, agentID string, sessionID string, persistLegacySession bool) (bool, error) {
	if !persistLegacySession {
		return service.AgentBelongsToMachine(ctx, machineID, agentID)
	}

	trimmedSessionID := strings.TrimSpace(sessionID)
	commandTag, err := service.db.Exec(ctx, `
UPDATE agents
SET session_id = $2,
    updated_at = NOW()
WHERE id = $1
  AND machine_id = $3
  AND status <> 'archived'
  AND COALESCE(session_id, '') <> $2
  AND EXISTS (
      SELECT 1
      FROM machines
      WHERE machines.id = agents.machine_id
        AND machines.status = 'active'
  )
`, agentID, trimmedSessionID, machineID)
	if err != nil {
		return false, fmt.Errorf("update legacy agent session mirror: %w", err)
	}
	if commandTag.RowsAffected() > 0 {
		return true, nil
	}
	return service.AgentBelongsToMachine(ctx, machineID, agentID)
}

// AgentBelongsToMachine reports whether the agent is owned by the given machine.
func (service *Service) AgentBelongsToMachine(ctx context.Context, machineID string, agentID string) (bool, error) {
	return agentBelongsToMachine(ctx, service.db, machineID, agentID)
}

// AgentNamesForMachine returns the public names of an active agent owned by
// the given active machine.
func (service *Service) AgentNamesForMachine(ctx context.Context, machineID string, agentID string) (string, string, bool, error) {
	var name string
	var displayName string
	err := service.db.QueryRow(ctx, `
SELECT agents.name, members.display_name
FROM agents
JOIN members ON members.id = agents.member_id
JOIN machines ON machines.id = agents.machine_id
WHERE agents.id = $1
  AND agents.machine_id = $2
  AND agents.status <> 'archived'
  AND machines.status = 'active'
`, strings.TrimSpace(agentID), strings.TrimSpace(machineID)).Scan(
		&name,
		&displayName,
	)
	if err != nil {
		if coredb.IsNotFound(err) {
			return "", "", false, nil
		}
		return "", "", false, fmt.Errorf("load agent names for machine: %w", err)
	}
	return strings.TrimSpace(name), strings.TrimSpace(displayName), true, nil
}

// MachineIDForAgent resolves the machine ID that owns the given agent within
// the given workspace. Returns empty string if the agent is not found.
func (service *Service) MachineIDForAgent(ctx context.Context, workspaceID string, agentID string) (string, error) {
	var machineID string
	err := service.db.QueryRow(ctx, `
SELECT machine_id
FROM agents
WHERE workspace_id = $1 AND id = $2 AND status <> 'archived'
`, strings.TrimSpace(workspaceID), strings.TrimSpace(agentID)).Scan(&machineID)
	if err != nil {
		if coredb.IsNotFound(err) {
			return "", nil
		}
		return "", fmt.Errorf("load agent machine id: %w", err)
	}
	return strings.TrimSpace(machineID), nil
}

// AgentPermissionModeForMachine returns an agent's runtime permission mode when
// the agent belongs to the given active machine.
func (service *Service) AgentPermissionModeForMachine(ctx context.Context, machineID string, agentID string) (string, bool, error) {
	var permissionMode string
	err := service.db.QueryRow(ctx, `
SELECT agents.permission_mode
FROM agents
JOIN machines ON machines.id = agents.machine_id
WHERE agents.id = $1
  AND agents.machine_id = $2
  AND agents.status <> 'archived'
  AND machines.status = 'active'
`, strings.TrimSpace(agentID), strings.TrimSpace(machineID)).Scan(&permissionMode)
	if err != nil {
		if coredb.IsNotFound(err) {
			return "", false, nil
		}
		return "", false, fmt.Errorf("load agent permission mode: %w", err)
	}
	return DefaultAgentPermissionMode(permissionMode), true, nil
}

// ClearWorkspaceWriteAgentAuthTokensForMachine is kept for old daemon
// handshakes. Workspace-write rows now launch as full access, so there are no
// restricted-mode bearer tokens to revoke.
func (service *Service) ClearWorkspaceWriteAgentAuthTokensForMachine(ctx context.Context, machineID string) error {
	_, _ = ctx, machineID
	return nil
}

func agentBelongsToMachine(ctx context.Context, queryer coredb.QueryRower, machineID string, agentID string) (bool, error) {
	var exists bool
	if err := queryer.QueryRow(ctx, `
SELECT EXISTS(
    SELECT 1
    FROM agents
    JOIN machines ON machines.id = agents.machine_id
    WHERE agents.id = $1
      AND agents.machine_id = $2
      AND agents.status <> 'archived'
      AND machines.status = 'active'
)
`, agentID, machineID).Scan(&exists); err != nil {
		return false, fmt.Errorf("check agent machine ownership: %w", err)
	}
	return exists, nil
}

func (service *Service) AgentRuntimeForStart(ctx context.Context, agentID string) (string, error) {
	var runtimeValue string
	if err := service.db.QueryRow(ctx, `
SELECT runtime
FROM agents
WHERE id = $1
  AND status <> 'archived'
`, strings.TrimSpace(agentID)).Scan(&runtimeValue); err != nil {
		if coredb.IsNotFound(err) {
			return "", ErrNotFound
		}
		return "", fmt.Errorf("load agent runtime for start: %w", err)
	}
	return strings.TrimSpace(runtimeValue), nil
}

func (service *Service) IssueAgentAuthTokenForMachine(ctx context.Context, machineID string, agentID string, allowWorkspaceWrite bool) (string, error) {
	_ = allowWorkspaceWrite
	trimmedMachineID := strings.TrimSpace(machineID)
	trimmedAgentID := strings.TrimSpace(agentID)
	if trimmedMachineID == "" || trimmedAgentID == "" {
		return "", ErrUnauthorized
	}

	authToken, err := secrets.NewToken(32)
	if err != nil {
		return "", fmt.Errorf("generate agent auth token: %w", err)
	}
	authTokenHash := secrets.HashToken(authToken)

	commandTag, err := service.db.Exec(ctx, `
UPDATE agents
SET auth_token_hash = $3,
    updated_at = NOW()
WHERE id = $1 AND machine_id = $2
  AND status <> 'archived'
  AND EXISTS (
      SELECT 1
      FROM machines
      WHERE machines.workspace_id = agents.workspace_id
        AND machines.id = agents.machine_id
        AND machines.status = 'active'
  )
`, trimmedAgentID, trimmedMachineID, authTokenHash)
	if err != nil {
		return "", fmt.Errorf("issue agent auth token: %w", err)
	}
	if commandTag.RowsAffected() == 0 {
		return "", ErrUnauthorized
	}
	return authToken, nil
}

func (service *Service) PrepareAgentStart(ctx context.Context, agentID string, allowWorkspaceWrite bool, includeLegacySession bool) (PreparedAgentStart, error) {
	_ = allowWorkspaceWrite
	var prepared PreparedAgentStart
	err := coredb.WithTx(ctx, service.db, func(tx coredb.Tx) error {
		authToken, err := secrets.NewToken(32)
		if err != nil {
			return fmt.Errorf("generate agent auth token: %w", err)
		}
		authTokenHash := secrets.HashToken(authToken)

		commandTag, err := tx.Exec(ctx, `
UPDATE agents
SET auth_token_hash = $2,
    updated_at = NOW()
WHERE id = $1
  AND status <> 'archived'
  AND EXISTS (
      SELECT 1
      FROM machines
      WHERE machines.workspace_id = agents.workspace_id
        AND machines.id = agents.machine_id
        AND machines.status = 'active'
  )
`, agentID, authTokenHash)
		if err != nil {
			return fmt.Errorf("update agent auth token for start: %w", err)
		}
		if commandTag.RowsAffected() == 0 {
			return ErrNotFound
		}

		startRow, err := loadPreparedAgentStartRow(ctx, tx, agentID, includeLegacySession)
		if err != nil {
			return err
		}
		prepared = startRow.Prepared
		prepared.PermissionMode = DefaultAgentPermissionMode(prepared.PermissionMode)

		memberRow := tx.QueryRow(ctx, `SELECT display_name FROM members WHERE id = $1`, startRow.MemberID)
		prepared.RuntimePolicy = NewRuntimePolicySnapshot(prepared.Runtime, prepared.PermissionMode, prepared.RuntimePolicy.Generation, prepared.VisibleReplyContractEnabled)
		prepared.ReasoningEffort = NormalizeReasoningEffortForRuntime(
			prepared.Runtime,
			prepared.ReasoningEffort,
		)

		if err := memberRow.Scan(&prepared.DisplayName); err != nil {
			return fmt.Errorf("load agent member: %w", err)
		}

		prepared.MemberID = startRow.MemberID
		decodedLLM, err := DecodeStoredAgentLLMColumnsWithFallback(
			service.credentialStorageKey,
			service.legacyCredentialStorageKeys,
			startRow.LLMMode,
			startRow.BaseURL,
			startRow.APIKeyCiphertext,
			startRow.HeadersJSON,
			startRow.WireAPI,
		)
		if err != nil {
			return fmt.Errorf("decode prepared agent llm: %w", err)
		}
		prepared.LLMMode, prepared.BaseURL, prepared.APIKey, prepared.Headers, prepared.WireAPI = AgentLLMFieldsFromStored(decodedLLM)
		prepared.AuthToken = authToken
		return nil
	})
	if err != nil {
		return PreparedAgentStart{}, err
	}
	return prepared, nil
}

func loadPreparedAgentStartRow(ctx context.Context, tx coredb.Tx, agentID string, includeLegacySession bool) (preparedAgentStartRow, error) {
	sessionColumn := `''`
	if includeLegacySession {
		sessionColumn = `a.session_id`
	}
	row := tx.QueryRow(ctx, `
SELECT a.id, w.organization_id, a.workspace_id, a.machine_id, a.member_id, a.name, a.runtime, a.permission_mode,
       a.runtime_policy_generation,
       a.visible_reply_contract_enabled, COALESCE(prefs.runtime_debug_enabled, FALSE),
       a.model, a.reasoning_effort,
       llm_mode, llm_base_url, llm_api_key_ciphertext, llm_headers_json, llm_wire_api,
       a.description, `+sessionColumn+`
FROM agents a
JOIN machines mac
  ON mac.workspace_id = a.workspace_id
 AND mac.id = a.machine_id
LEFT JOIN user_preferences prefs
  ON prefs.user_id = mac.created_by_user_id
JOIN workspaces w
  ON w.id = a.workspace_id
WHERE a.id = $1
  AND a.status <> 'archived'
  AND mac.status = 'active'
`, agentID)

	var startRow preparedAgentStartRow
	if err := row.Scan(
		&startRow.Prepared.AgentID,
		&startRow.Prepared.OrganizationID,
		&startRow.Prepared.WorkspaceID,
		&startRow.Prepared.MachineID,
		&startRow.MemberID,
		&startRow.Prepared.Name,
		&startRow.Prepared.Runtime,
		&startRow.Prepared.PermissionMode,
		&startRow.Prepared.RuntimePolicy.Generation,
		&startRow.Prepared.VisibleReplyContractEnabled,
		&startRow.Prepared.RuntimeDebugEnabled,
		&startRow.Prepared.Model,
		&startRow.Prepared.ReasoningEffort,
		&startRow.LLMMode,
		&startRow.BaseURL,
		&startRow.APIKeyCiphertext,
		&startRow.HeadersJSON,
		&startRow.WireAPI,
		&startRow.Prepared.Description,
		&startRow.Prepared.SessionID,
	); err != nil {
		if coredb.IsNotFound(err) {
			return preparedAgentStartRow{}, ErrNotFound
		}
		return preparedAgentStartRow{}, fmt.Errorf("load prepared agent start: %w", err)
	}
	return startRow, nil
}

func rollback(tx coredb.Tx, ctx context.Context) {
	_ = tx.Rollback(ctx)
}
