package app

import (
	"context"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/message"
	"github.com/tidbcloud/AgentTeam/internal/workflow/orchestrator"
)

// workflowMemberContextToWire converts the frozen runtime member context into
// the durable wire shape persisted in message metadata.
func workflowMemberContextToWire(context *orchestrator.CallbackTeamMemberContext) *message.WorkflowTeamMemberContextWire {
	if context == nil {
		return nil
	}
	return &message.WorkflowTeamMemberContextWire{
		TeamID:          context.TeamID,
		TeamHandle:      context.TeamHandle,
		TeamDisplayName: context.TeamDisplayName,
		TeamPurpose:     context.TeamPurpose,
		TeamMemberID:    context.TeamMemberID,
		Role:            context.Role,
		RoleLabel:       context.RoleLabel,
		RoleOverlay:     context.RoleOverlay,
	}
}

// ResolveWorkflowRunTeamMember resolves the minimal, server-authorized member
// context for a callback responder of a Run with a frozen Team ID (Team-linked
// binding or dynamic-explicit teamId). It verifies the responder is a valid,
// active Agent member of the frozen Run Team and returns ONLY that responder's
// own membership: Team identity/purpose, the responder's stable TeamMember id,
// role, role label, and role overlay. It never returns the team roster, other
// members' duties, or wake configuration.
//
// It fails closed: an inactive Team, an unknown/archived responder Agent, or a
// responder who is not a current member of the Team returns an error so a
// Workflow step can never be delivered under a forged Team membership.
func (store *Store) ResolveWorkflowRunTeamMember(ctx context.Context, workspaceID string, teamID string, responderAgentID string) (*orchestrator.CallbackTeamMemberContext, error) {
	workspaceID = strings.TrimSpace(workspaceID)
	teamID = strings.TrimSpace(teamID)
	responderAgentID = strings.TrimSpace(responderAgentID)
	if workspaceID == "" || teamID == "" || responderAgentID == "" {
		return nil, badRequest("workflow Run Team member resolution requires workspace, team, and responder")
	}
	return resolveWorkflowRunTeamMemberWithQueryer(ctx, store.db, workspaceID, teamID, responderAgentID)
}

// resolveWorkflowRunTeamMemberWithQueryer is the shared server-side resolver
// used both by the public resolver (with store.db) and by the message write
// transaction (with the write tx). It returns the frozen minimal member
// context only after proving the Team is active and the responder is a valid,
// active Agent member of that Team.
func resolveWorkflowRunTeamMemberWithQueryer(ctx context.Context, queryer coredb.Queryer, workspaceID string, teamID string, responderAgentID string) (*orchestrator.CallbackTeamMemberContext, error) {
	var teamHandle, teamDisplayName, teamDescription string
	err := queryer.QueryRow(ctx, `
SELECT handle, display_name, COALESCE(description, '')
FROM workspace_teams
WHERE workspace_id = $1
  AND id = $2
  AND status = 'active'
LIMIT 1
`, workspaceID, teamID).Scan(&teamHandle, &teamDisplayName, &teamDescription)
	if err != nil {
		if coredb.IsNotFound(err) {
			return nil, forbidden("workflow Run Team is not active or not visible")
		}
		return nil, err
	}

	var teamMemberID, role, roleLabel, roleOverlay string
	err = queryer.QueryRow(ctx, `
SELECT wtm.id, wtm.role, COALESCE(wtm.role_label, ''), COALESCE(wtm.role_overlay_prompt, '')
FROM workspace_team_members wtm
JOIN agents a
  ON a.workspace_id = wtm.workspace_id
 AND a.member_id = wtm.actor_id
WHERE wtm.workspace_id = $1
  AND wtm.team_id = $2
  AND wtm.actor_kind = 'agent'
  AND wtm.removed_at IS NULL
  AND a.id = $3
  AND a.status <> 'archived'
LIMIT 1
`, workspaceID, teamID, responderAgentID).Scan(&teamMemberID, &role, &roleLabel, &roleOverlay)
	if err != nil {
		if coredb.IsNotFound(err) {
			return nil, forbidden("workflow Run responder is not an active Team member")
		}
		return nil, err
	}

	return &orchestrator.CallbackTeamMemberContext{
		TeamID:          teamID,
		TeamHandle:      strings.TrimSpace(teamHandle),
		TeamDisplayName: strings.TrimSpace(teamDisplayName),
		TeamPurpose:     strings.TrimSpace(teamDescription),
		TeamMemberID:    strings.TrimSpace(teamMemberID),
		Role:            strings.TrimSpace(role),
		RoleLabel:       strings.TrimSpace(roleLabel),
		RoleOverlay:     strings.TrimSpace(roleOverlay),
	}, nil
}
