package orchestrator

import (
	"context"
	"fmt"
	"strings"

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

// HumanApprovalAssigneeResolver resolves an authoring reference at dispatch
// time, before the result is frozen on the leased effect. Exact member IDs
// are authoritative; display/user aliases must resolve to exactly one active
// Human in the Run workspace. The Workflow App itself never repeats this
// mutable alias resolution and trusts only the subsequently frozen member ID.
type HumanApprovalAssigneeResolver struct {
	directory coredb.Queryer
}

func NewHumanApprovalAssigneeResolver(directory coredb.Queryer) (*HumanApprovalAssigneeResolver, error) {
	if directory == nil {
		return nil, fmt.Errorf("workflow approval Human directory is required")
	}
	return &HumanApprovalAssigneeResolver{directory: directory}, nil
}

func (resolver *HumanApprovalAssigneeResolver) ResolveWorkflowApprovalAssignee(ctx context.Context, workspaceID, reference string) (string, error) {
	if resolver == nil || resolver.directory == nil {
		return "", fmt.Errorf("workflow approval Human directory is not configured")
	}
	workspaceID = strings.TrimSpace(workspaceID)
	reference = strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(reference), "@"))
	if workspaceID == "" || reference == "" {
		return "", fmt.Errorf("workflow approval workspace and assignee are required")
	}

	var exact string
	err := resolver.directory.QueryRow(ctx, `
SELECT id
FROM members
WHERE workspace_id=$1 AND id=$2 AND type='human' AND status='active'
LIMIT 1`, workspaceID, reference).Scan(&exact)
	if err == nil {
		return strings.TrimSpace(exact), nil
	}
	if !coredb.IsNotFound(err) {
		return "", fmt.Errorf("resolve exact workflow approval assignee: %w", err)
	}

	rows, err := resolver.directory.Query(ctx, `
SELECT member.id
FROM members member
JOIN users human_user ON human_user.id=member.user_id
WHERE member.workspace_id=$1
  AND member.type='human' AND member.status='active'
  AND (
    LOWER(member.display_name)=LOWER($2)
    OR LOWER(human_user.name)=LOWER($2)
    OR LOWER(human_user.display_name)=LOWER($2)
    OR LOWER(COALESCE(human_user.email,''))=LOWER($2)
  )
ORDER BY member.id ASC
LIMIT 2`, workspaceID, reference)
	if err != nil {
		return "", fmt.Errorf("resolve workflow approval assignee alias: %w", err)
	}
	defer rows.Close()
	matches := make([]string, 0, 2)
	for rows.Next() {
		var memberID string
		if err := rows.Scan(&memberID); err != nil {
			return "", fmt.Errorf("scan workflow approval assignee: %w", err)
		}
		memberID = strings.TrimSpace(memberID)
		if memberID != "" {
			matches = append(matches, memberID)
		}
	}
	if err := rows.Err(); err != nil {
		return "", fmt.Errorf("iterate workflow approval assignees: %w", err)
	}
	switch len(matches) {
	case 1:
		return matches[0], nil
	case 0:
		return "", fmt.Errorf("workflow approval assignee %q was not found as an active Human", reference)
	default:
		return "", fmt.Errorf("workflow approval assignee %q is ambiguous; use an exact member ID", reference)
	}
}

var _ ApprovalAssigneeResolver = (*HumanApprovalAssigneeResolver)(nil)
