package invocation

import (
	"context"
	"fmt"
	"strings"

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

// resolveRunTeamID returns the server-authorized Team that owns a Team-linked
// Plan, from the durable workspace_team_workflows relation, or "" when the Plan
// is not Team-linked. Only a relation whose first version was APPROVED and
// ACTIVATED (activated_at set by the approval lifecycle) and is not deleted
// yields a Team ID, so a bound-but-never-approved, rejected, or deleted
// relation can never pin a Run to a Team. The frozen Team ID therefore cannot
// be forged from visible text or a callback.
func resolveRunTeamID(ctx context.Context, queryer coredb.Queryer, workspaceID string, planID string) (string, error) {
	var teamID string
	err := queryer.QueryRow(ctx, `
SELECT team_id
FROM workspace_team_workflows
WHERE workspace_id = $1
  AND plan_id = $2
  AND deleted_at IS NULL
  AND activated_at IS NOT NULL
LIMIT 1
`, strings.TrimSpace(workspaceID), strings.TrimSpace(planID)).Scan(&teamID)
	if err != nil {
		if coredb.IsNotFound(err) {
			return "", nil
		}
		return "", fmt.Errorf("resolve workflow Run team: %w", err)
	}
	return strings.TrimSpace(teamID), nil
}

// authorizeManualInvocationTeam verifies the invokedBy actor is a valid, active
// member of the requested Team before an unlinked/dynamic Run freezes that Team
// ID. A human invokes through their workspace member; an Agent invokes through
// its Agent member. It fails closed so an explicit Team ID can never be frozen
// without the caller holding real Team membership.
func authorizeManualInvocationTeam(ctx context.Context, execer coredb.QueryExecer, workspaceID string, teamID string, invokedBy Actor) error {
	workspaceID = strings.TrimSpace(workspaceID)
	teamID = strings.TrimSpace(teamID)
	if workspaceID == "" || teamID == "" {
		return storeerr.BadRequest("workflow invocation Team ID requires workspace and team")
	}
	memberID := strings.TrimSpace(invokedBy.MemberID)
	if memberID == "" {
		return storeerr.Forbidden("workflow invocation Team authorization requires the caller member")
	}
	var exists int
	err := execer.QueryRow(ctx, `
SELECT 1
FROM workspace_team_members wtm
JOIN workspace_teams t
  ON t.workspace_id = wtm.workspace_id
 AND t.id = wtm.team_id
 AND t.status = 'active'
JOIN members m
  ON m.workspace_id = wtm.workspace_id
 AND m.id = wtm.actor_id
WHERE wtm.workspace_id = $1
  AND wtm.team_id = $2
  AND wtm.removed_at IS NULL
  AND m.id = $3
  AND m.status = 'active'
LIMIT 1
`, workspaceID, teamID, memberID).Scan(&exists)
	if err != nil {
		if coredb.IsNotFound(err) {
			return storeerr.Forbidden("workflow invocation caller is not an active member of an active Team")
		}
		return fmt.Errorf("authorize workflow invocation Team: %w", err)
	}
	return nil
}

func insertRun(ctx context.Context, execer coredb.QueryExecer, value Run) error {
	var teamID any
	if trimmedTeamID := strings.TrimSpace(value.TeamID); trimmedTeamID != "" {
		teamID = trimmedTeamID
	}
	_, err := execer.Exec(ctx, `
INSERT INTO workflow_run_instances (
    id, workspace_id, invocation_id,
    plan_id, plan_version_id, team_id, workflow_name_snapshot, status, input_json, input_digest,
	state_json, last_event_seq, runnable_at,
    owner_user_id_snapshot, owner_member_id_snapshot,
    principal_member_id_snapshot, author_member_id_snapshot,
    queued_at, created_at, updated_at
) VALUES (
    $1, $2, $3,
    $4, $5, $14, $6, 'queued', $7, $8,
	'{}', 1, $13,
    $9, $10,
    $11, $12,
	$13, $13, $13
)
`, value.ID, value.WorkspaceID, value.InvocationID,
		value.PlanID, value.PlanVersionID, value.WorkflowNameSnapshot, value.InputJSON, value.InputDigest,
		value.Identity.OwnerUserID, value.Identity.OwnerMemberID,
		value.Identity.PrincipalMemberID, value.Identity.AuthorMemberID,
		value.QueuedAt, teamID)
	if err != nil {
		if coredb.IsUniqueViolation(err) {
			return storeerr.Conflict("workflow Run already exists for Invocation")
		}
		if coredb.IsForeignKeyViolation(err) {
			return ErrDeploymentChanged
		}
		return fmt.Errorf("insert queued workflow Run: %w", err)
	}
	return nil
}
