package mail

import (
	"github.com/tidbcloud/AgentTeam/internal/extension/registry"
	"github.com/tidbcloud/AgentTeam/internal/extension/spec"
)

func mailActions() []registry.DefinitionAction {
	return []registry.DefinitionAction{
		searchMessagesAction(),
		getMessageAction(),
		listAttachmentsAction(),
		getAttachmentAction(),
		createDraftAction(),
		updateDraftAction(),
		createReplyDraftAction(),
		createForwardDraftAction(),
		sendDraftAction(),
	}
}

func searchMessagesAction() registry.DefinitionAction {
	return registry.DefinitionAction{
		Name:           ActionSearchMessages,
		Summary:        "Search mailbox messages",
		Description:    "Search one bounded page of untrusted message metadata with provider-neutral filters.",
		Safety:         spec.Safety{Class: "read", Idempotent: true},
		RequiredScopes: []string{ScopeMetadataRead},
		InputSchema: objectSchema(map[string]any{
			"filters": searchFiltersSchema(),
			"limit":   map[string]any{"type": "integer", "minimum": 1, "maximum": 50},
			"cursor":  nonEmptyStringSchema(2048),
		}, []any{"filters"}),
		OutputSchema: searchOutputSchema(),
		Example: map[string]any{
			"filters": map[string]any{
				"text":           "renewal",
				"folder":         "inbox",
				"from":           []any{"customer@example.com"},
				"receivedAfter":  "2026-08-01T00:00:00Z",
				"unread":         true,
				"hasAttachments": false,
			},
			"limit": 20,
		},
	}
}

func getMessageAction() registry.DefinitionAction {
	return registry.DefinitionAction{
		Name:           ActionGetMessage,
		Summary:        "Read one mailbox message",
		Description:    "Read a bounded normalized untrusted message body by opaque Mail resource alias; HTML is sanitized by the server.",
		Safety:         spec.Safety{Class: "read", Idempotent: true},
		RequiredScopes: []string{ScopeMetadataRead, ScopeContentRead},
		InputSchema: objectSchema(map[string]any{
			"message": resourceAliasSchema(),
		}, []any{"message"}),
		OutputSchema: messageOutputSchema(),
		Example:      map[string]any{"message": "mailmsg_example"},
	}
}

func listAttachmentsAction() registry.DefinitionAction {
	return registry.DefinitionAction{
		Name:           ActionListAttachments,
		Summary:        "List message attachments",
		Description:    "List untrusted attachment metadata and opaque aliases usable with get-attachment, without returning binary content.",
		Safety:         spec.Safety{Class: "read", Idempotent: true},
		RequiredScopes: []string{ScopeMetadataRead, ScopeContentRead},
		InputSchema: objectSchema(map[string]any{
			"message": resourceAliasSchema(),
		}, []any{"message"}),
		OutputSchema: objectSchema(map[string]any{
			"attachments": map[string]any{
				"type":     "array",
				"maxItems": 100,
				"items":    attachmentMetadataSchema(),
			},
			"truncated": booleanSchema(),
		}, []any{"attachments", "truncated"}),
		Example: map[string]any{"message": "mailmsg_example"},
	}
}

func getAttachmentAction() registry.DefinitionAction {
	return registry.DefinitionAction{
		Name:           ActionGetAttachment,
		Summary:        "Import one message attachment into AgentTeam",
		Description:    "Read the exact bounded MIME part behind an opaque attachment alias and materialize it as a AgentTeam attachment in an explicit conversation target. The result carries only the AgentTeam attachment ID, never raw bytes. Materializing writes a AgentTeam attachment, so this Action is a mutation even though the mailbox itself is only read. An unknown result means the upload may or may not have happened: reread before acting and never retry automatically.",
		Safety:         spec.Safety{Class: "mutation"},
		RequiredScopes: []string{ScopeMetadataRead, ScopeContentRead},
		InputSchema: objectSchema(map[string]any{
			"attachment": resourceAliasSchema(),
			"target":     nonEmptyStringSchema(2048),
		}, []any{"attachment", "target"}),
		OutputSchema: getAttachmentOutputSchema(),
		Example:      map[string]any{"attachment": "mailatt_example", "target": "#general"},
	}
}

func createDraftAction() registry.DefinitionAction {
	return registry.DefinitionAction{
		Name:           ActionCreateDraft,
		Summary:        "Create an email draft",
		Description:    "Create a draft in the authorized mailbox, optionally binding AgentTeam attachments the invoking agent can already read. Each attachment is referenced by AgentTeam attachment ID only; paths and provider URLs are never accepted. At most 10 attachments, 10 MiB each and 20 MiB total.",
		Safety:         spec.Safety{Class: "mutation"},
		RequiredScopes: []string{ScopeDraftWrite},
		InputSchema:    createDraftInputSchema(),
		OutputSchema:   draftOutputSchema(),
		Example: map[string]any{
			"clientRequestId": "req_create_1",
			"to":              []any{"customer@example.com"},
			"subject":         "Project update",
			"body":            map[string]any{"format": "text", "content": "Hello"},
			"attachments":     []any{map[string]any{"attachmentId": "att_example"}},
		},
	}
}

func updateDraftAction() registry.DefinitionAction {
	return registry.DefinitionAction{
		Name:           ActionUpdateDraft,
		Summary:        "Update an email draft",
		Description:    "Replace one exact draft revision, rebinding its attachments from AgentTeam attachment IDs under the same limits.",
		Safety:         spec.Safety{Class: "mutation"},
		RequiredScopes: []string{ScopeDraftWrite},
		InputSchema:    updateDraftInputSchema(),
		OutputSchema:   draftOutputSchema(),
		Example: map[string]any{
			"clientRequestId":  "req_update_1",
			"draft":            "maildraft_example",
			"expectedRevision": 1,
			"to":               []any{"customer@example.com"},
			"subject":          "Updated project status",
			"body":             map[string]any{"format": "text", "content": "Updated"},
		},
	}
}

func createReplyDraftAction() registry.DefinitionAction {
	return registry.DefinitionAction{
		Name:           ActionCreateReplyDraft,
		Summary:        "Create a reply draft",
		Description:    "Create a reply draft from one authorized source message, optionally binding AgentTeam attachments the invoking agent can already read.",
		Safety:         spec.Safety{Class: "mutation"},
		RequiredScopes: []string{ScopeMetadataRead, ScopeContentRead, ScopeDraftWrite},
		InputSchema: objectSchema(map[string]any{
			"clientRequestId": clientRequestIDSchema(),
			"message":         resourceAliasSchema(),
			"replyAll":        map[string]any{"type": "boolean"},
			"body":            bodySchema(),
			"attachments":     draftAttachmentsSchema(),
		}, []any{"clientRequestId", "message", "body"}),
		OutputSchema: draftOutputSchema(),
		Example: map[string]any{
			"clientRequestId": "req_reply_1",
			"message":         "mailmsg_example",
			"body":            map[string]any{"format": "text", "content": "Thanks"},
		},
	}
}

func createForwardDraftAction() registry.DefinitionAction {
	return registry.DefinitionAction{
		Name:           ActionCreateForwardDraft,
		Summary:        "Create a forward draft",
		Description:    "Create a forward draft that copies the source message attachments and may add AgentTeam attachments the invoking agent can already read, under the shared count and size limits.",
		Safety:         spec.Safety{Class: "mutation"},
		RequiredScopes: []string{ScopeMetadataRead, ScopeContentRead, ScopeDraftWrite},
		InputSchema: objectSchema(map[string]any{
			"clientRequestId": clientRequestIDSchema(),
			"message":         resourceAliasSchema(),
			"to":              addressSetSchema(),
			"cc":              addressSetSchema(),
			"bcc":             addressSetSchema(),
			"body":            bodySchema(),
			"attachments":     draftAttachmentsSchema(),
		}, []any{"clientRequestId", "message", "to", "body"}),
		OutputSchema: draftOutputSchema(),
		Example: map[string]any{
			"clientRequestId": "req_forward_1",
			"message":         "mailmsg_example",
			"to":              []any{"colleague@example.com"},
			"body":            map[string]any{"format": "text", "content": "For context"},
		},
	}
}

func sendDraftAction() registry.DefinitionAction {
	return registry.DefinitionAction{
		Name:           ActionSendDraft,
		Summary:        "Send one frozen draft revision over SMTP",
		Description:    "Send the exact draft revision, including its attachments, over the connection's SMTP provider. The provider is attempted exactly once; an inconclusive result is reported as unknown and must not be retried automatically. Whether a Sent copy is kept is decided by the provider.",
		Safety:         spec.Safety{Class: "mutation"},
		RequiredScopes: []string{ScopeDraftWrite, ScopeSend},
		InputSchema: objectSchema(map[string]any{
			"clientRequestId":  clientRequestIDSchema(),
			"draft":            resourceAliasSchema(),
			"expectedRevision": map[string]any{"type": "integer", "minimum": 1},
		}, []any{"clientRequestId", "draft", "expectedRevision"}),
		OutputSchema: objectSchema(map[string]any{
			"status":         map[string]any{"type": "string", "enum": []any{"accepted", "failed", "unknown"}},
			"recipientCount": map[string]any{"type": "integer", "minimum": 1},
			"subjectExcerpt": map[string]any{"type": "string", "maxLength": 160},
			"truncated":      booleanSchema(),
		}, []any{"status", "recipientCount", "truncated"}),
		Example: map[string]any{
			"clientRequestId":  "req_send_1",
			"draft":            "maildraft_example",
			"expectedRevision": 2,
		},
	}
}
