package run

import (
	"context"
	"strings"

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

// AuthorizeCallbackAgent is the durable callback authority boundary. A
// callback grant is the exact frozen Agent on the effect, and it remains
// usable only while the canonical Agent member, machine, and managing
// Human owner are active and still match the frozen Run principal.
func (store *Store) AuthorizeCallbackAgent(ctx context.Context, principal AgentPrincipal, workspaceID, runID, effectID string) error {
	if err := store.Validate(); err != nil {
		return err
	}
	return authorizeCallbackAgentQuery(ctx, store.db, principal, workspaceID, runID, effectID)
}

// AuthorizeCallbackAgentTx is the transaction-aware form used by callback
// mutations after Run/Activation/Effect are locked. It closes the TOCTOU gap
// between an ordinary callback read and pause/park/complete/fail commits.
func (store *Store) AuthorizeCallbackAgentTx(ctx context.Context, tx coredb.Tx, principal AgentPrincipal, workspaceID, runID, effectID string) error {
	if err := store.Validate(); err != nil {
		return err
	}
	if tx == nil {
		return storeerr.BadRequest("transaction is required")
	}
	return authorizeCallbackAgentQuery(ctx, tx, principal, workspaceID, runID, effectID)
}

func authorizeCallbackAgentQuery(ctx context.Context, queryer coredb.QueryRower, principal AgentPrincipal, workspaceID, runID, effectID string) error {
	workspaceID = strings.TrimSpace(workspaceID)
	runID = strings.TrimSpace(runID)
	effectID = strings.TrimSpace(effectID)
	principal.WorkspaceID = strings.TrimSpace(principal.WorkspaceID)
	principal.AgentID = strings.TrimSpace(principal.AgentID)
	principal.MemberID = strings.TrimSpace(principal.MemberID)
	if queryer == nil || workspaceID == "" || runID == "" || effectID == "" ||
		principal.WorkspaceID == "" || principal.WorkspaceID != workspaceID ||
		principal.AgentID == "" || principal.MemberID == "" {
		return storeerr.NotFound("workflow Run callback not found")
	}
	var authorized int
	err := queryer.QueryRow(ctx, `
SELECT 1
FROM workflow_run_effects effect
JOIN workflow_run_instances run
  ON run.workspace_id=effect.workspace_id AND run.id=effect.run_id
JOIN agents responder_agent
  ON responder_agent.workspace_id=effect.workspace_id
 AND responder_agent.id=effect.callback_responder_agent_id
 AND responder_agent.id=$4
 AND responder_agent.member_id=$5
 AND responder_agent.status <> 'archived'
JOIN members responder_member
  ON responder_member.workspace_id=responder_agent.workspace_id
 AND responder_member.id=responder_agent.member_id
 AND responder_member.type='agent'
 AND responder_member.status='active'
JOIN machines responder_machine
  ON responder_machine.workspace_id=responder_agent.workspace_id
 AND responder_machine.id=responder_agent.machine_id
 AND responder_machine.status='active'
JOIN members current_owner
  ON current_owner.workspace_id=responder_machine.workspace_id
 AND current_owner.user_id=responder_machine.created_by_user_id
 AND current_owner.type='human'
 AND current_owner.status='active'
WHERE effect.workspace_id=$1
  AND effect.run_id=$2
  AND effect.id=$3
  AND effect.effect_kind='send_message'
  AND effect.callback_responder_agent_id=$4
  AND run.principal_member_id_snapshot=current_owner.id
LIMIT 1
FOR UPDATE
`, workspaceID, runID, effectID, principal.AgentID, principal.MemberID).Scan(&authorized)
	if err != nil {
		if coredb.IsNotFound(err) {
			return storeerr.NotFound("workflow Run callback not found")
		}
		return err
	}
	if authorized != 1 {
		return storeerr.NotFound("workflow Run callback not found")
	}
	return nil
}
