package exec

import (
	"context"
	"strings"
)

type teamListInput struct {
	Query  string `json:"query,omitempty" jsonschema:"maxLength=256"`
	Limit  int    `json:"limit,omitempty" jsonschema:"minimum=1,maximum=100"`
	Cursor string `json:"cursor,omitempty" jsonschema:"maxLength=512"`
}

type teamListItem struct {
	TeamID      string `json:"teamId"`
	Name        string `json:"name"`
	Handle      string `json:"handle"`
	Description string `json:"description,omitempty"`
	Role        string `json:"role"`
}

type teamListOutput struct {
	Teams      []teamListItem `json:"teams"`
	HasMore    bool           `json:"hasMore"`
	NextCursor string         `json:"nextCursor,omitempty"`
}

var teamListSpec = actionSpec[teamListInput, teamListOutput]{
	Meta: actionMeta{
		Domain:      "team",
		Name:        "list",
		Summary:     "list Teams available to the current Agent",
		Description: "List the Teams available to the current Agent.",
		Permission:  permissionReadOnly,
	},
	Examples: []actionExample[teamListInput]{
		{Title: "available Teams page", Input: teamListInput{Limit: 20, Cursor: "<nextCursor>"}},
	},
}

type teamGetInput struct {
	TeamID string `json:"teamId" jsonschema:"minLength=1"`
}

type teamDetail struct {
	TeamID      string       `json:"teamId"`
	Name        string       `json:"name"`
	Description string       `json:"description"`
	Members     []teamMember `json:"members"`
}

type teamMember struct {
	TeamMemberID      string `json:"teamMemberId"`
	AgentID           string `json:"agentId"`
	DisplayName       string `json:"displayName"`
	RoleLabel         string `json:"roleLabel,omitempty"`
	RoleOverlayPrompt string `json:"roleOverlayPrompt"`
	WakeOnTeamMention bool   `json:"wakeOnTeamMention"`
}

type teamGetOutput struct {
	Team teamDetail `json:"team"`
}

var teamGetSpec = actionSpec[teamGetInput, teamGetOutput]{
	Meta: actionMeta{
		Domain:      "team",
		Name:        "get",
		Summary:     "get one Team and its Agent members",
		Description: "Get one Team's basic information and existing Agent collaboration fields.",
		Permission:  permissionReadOnly,
	},
	Examples: []actionExample[teamGetInput]{
		{Title: "Team detail", Input: teamGetInput{TeamID: "team_0123456789abcd"}},
	},
}

type teamUpdateInput struct {
	TeamID        string             `json:"teamId" jsonschema:"minLength=1"`
	RequestID     string             `json:"requestId" jsonschema:"minLength=1,maxLength=128,pattern=.*\\S.*"`
	Description   *string            `json:"description,omitempty"`
	MemberUpdates []teamMemberUpdate `json:"memberUpdates,omitempty"`
}

type teamMemberUpdate struct {
	TeamMemberID      string  `json:"teamMemberId" jsonschema:"minLength=1"`
	RoleLabel         *string `json:"roleLabel,omitempty"`
	RoleOverlayPrompt *string `json:"roleOverlayPrompt,omitempty"`
	WakeOnTeamMention *bool   `json:"wakeOnTeamMention,omitempty"`
}

type teamUpdateRequest struct {
	TeamID        string             `json:"teamId"`
	RequestID     string             `json:"requestId"`
	Description   *string            `json:"description,omitempty"`
	MemberUpdates []teamMemberUpdate `json:"memberUpdates,omitempty"`
}

type teamUpdateOutput struct {
	Status string `json:"status"`
}

var teamUpdateSpec = func() actionSpec[teamUpdateInput, teamUpdateOutput] {
	description := "Coordinate backend delivery."
	return actionSpec[teamUpdateInput, teamUpdateOutput]{
		Meta: actionMeta{
			Domain:      "team",
			Name:        "update",
			Summary:     "request updates to one Team",
			Description: "Request Human-approved updates to a Team description or existing Agent member collaboration fields.",
			Permission:  permissionAgentScopedMutation,
		},
		Examples: []actionExample[teamUpdateInput]{
			{
				Title: "update Team description",
				Input: teamUpdateInput{
					TeamID: "team_0123456789abcd", RequestID: "request-1",
					Description: &description,
				},
			},
		},
	}
}()

type teamRuntime interface {
	list(context.Context, teamListInput) (teamListOutput, error)
	get(context.Context, string) (teamGetOutput, error)
	update(context.Context, string, teamUpdateRequest) (teamUpdateOutput, error)
}

type teamHandler struct {
	remote  teamRuntime
	read    remoteReadTransport
	receipt requestReceiptTransport
}

func (handler teamHandler) list(ctx context.Context, request actionScopedJSON[teamListInput]) (actionResult[teamListOutput], error) {
	input := request.Body
	input.Query = strings.TrimSpace(input.Query)
	input.Cursor = strings.TrimSpace(input.Cursor)
	if input.Limit <= 0 {
		input.Limit = 20
	}
	if input.Limit > 100 {
		input.Limit = 100
	}
	result, err := handler.runtime(request.Authorized).list(ctx, input)
	if err != nil {
		return actionResult[teamListOutput]{}, classifyAPIError(err, "list Teams failed")
	}
	if result.Teams == nil {
		result.Teams = []teamListItem{}
	}
	return actionResult[teamListOutput]{Data: result, Text: "Listed Teams."}, nil
}

func (handler teamHandler) get(ctx context.Context, request actionScopedJSON[teamGetInput]) (actionResult[teamGetOutput], error) {
	teamID := strings.TrimSpace(request.Body.TeamID)
	if teamID == "" {
		return actionResult[teamGetOutput]{}, NewError(CodeValidation, "teamId is required")
	}
	result, err := handler.runtime(request.Authorized).get(ctx, teamID)
	if err != nil {
		return actionResult[teamGetOutput]{}, classifyAPIError(err, "get Team failed")
	}
	if result.Team.Members == nil {
		result.Team.Members = []teamMember{}
	}
	return actionResult[teamGetOutput]{Data: result, Text: "Fetched Team."}, nil
}

func (handler teamHandler) update(ctx context.Context, request actionScopedJSON[teamUpdateInput]) (actionResult[teamUpdateOutput], error) {
	input := request.Body
	teamID := strings.TrimSpace(input.TeamID)
	requestID := strings.TrimSpace(input.RequestID)
	if teamID == "" || requestID == "" {
		return actionResult[teamUpdateOutput]{}, NewError(CodeValidation, "teamId and requestId are required")
	}
	if input.Description == nil && len(input.MemberUpdates) == 0 {
		return actionResult[teamUpdateOutput]{}, NewError(CodeValidation, "description or memberUpdates is required")
	}
	result, err := handler.runtime(request.Authorized).update(ctx, teamID, teamUpdateRequest{
		TeamID: teamID, RequestID: requestID, Description: input.Description, MemberUpdates: input.MemberUpdates,
	})
	if err != nil {
		return actionResult[teamUpdateOutput]{}, classifyAPIError(err, "update Team failed")
	}
	return actionResult[teamUpdateOutput]{Data: result, Text: "Requested Team update."}, nil
}

func (handler teamHandler) runtime(authorized runtimeAuthorization) teamRuntime {
	if handler.remote != nil {
		return handler.remote
	}
	return teamRemote{client: authorized.Server, read: handler.read, receipt: handler.receipt}
}
