package gitea

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

const (
	// Provider is the immutable provider identity bound by this Definition and
	// its executor. It is never accepted from Agent input.
	Provider = "gitea"
	// Revision is included in the Builtin digest and must change whenever
	// execution behavior changes incompatibly.
	Revision = "pull-request-watch-v1"
)

// Definition returns Gitea's independently owned Builtin Action catalog.
func Definition() registry.Definition {
	return registry.Definition{
		Domain:      Provider,
		Version:     1,
		Name:        "Gitea Pull Request Watches",
		Description: "Create and manage Gitea pull request watches in AgentTeam.",
		Actions: []registry.DefinitionAction{
			{
				Name:         prwatch.ActionWatchPullRequest,
				Summary:      "Watch a Gitea pull request",
				Description:  "Create or reuse a watch that delivers Gitea pull request activity to one authorized AgentTeam target.",
				Safety:       spec.Safety{Class: "mutation", Idempotent: true},
				InputSchema:  watchInputSchema(),
				OutputSchema: watchOutputSchema(),
				Example:      map[string]any{"pullRequest": "pingcap/agentteam#42"},
			},
			{
				Name:         prwatch.ActionListWatches,
				Summary:      "List Gitea pull request watches",
				Description:  "List one bounded page of watches owned by the authenticated Agent principal and Gitea App Installation.",
				Safety:       spec.Safety{Class: "read", Idempotent: true},
				InputSchema:  listInputSchema(),
				OutputSchema: listOutputSchema(),
				Example:      map[string]any{},
			},
			{
				Name:         prwatch.ActionPauseWatch,
				Summary:      "Pause a Gitea pull request watch",
				Description:  "Pause one exact Gitea watch by watch ID or target and pull request.",
				Safety:       spec.Safety{Class: "mutation"},
				InputSchema:  mutationInputSchema(),
				OutputSchema: mutationOutputSchema("paused"),
				Example:      map[string]any{"watchId": "pwt_example"},
			},
			{
				Name:         prwatch.ActionResumeWatch,
				Summary:      "Resume a Gitea pull request watch",
				Description:  "Resume one exact paused Gitea watch by watch ID or target and pull request.",
				Safety:       spec.Safety{Class: "mutation"},
				InputSchema:  mutationInputSchema(),
				OutputSchema: mutationOutputSchema("resumed"),
				Example:      map[string]any{"watchId": "pwt_example"},
			},
			{
				Name:         prwatch.ActionUnwatch,
				Summary:      "Remove a Gitea pull request watch",
				Description:  "Remove one exact Gitea watch by watch ID or target and pull request.",
				Safety:       spec.Safety{Class: "mutation"},
				InputSchema:  mutationInputSchema(),
				OutputSchema: mutationOutputSchema("deleted"),
				Example:      map[string]any{"watchId": "pwt_example"},
			},
		},
	}
}

func watchInputSchema() map[string]any {
	return objectSchema(
		map[string]any{
			"target":          nonEmptyStringSchema(),
			"pullRequest":     nonEmptyStringSchema(),
			"events":          stringSetSchema(),
			"notifyPrincipal": map[string]any{"type": "boolean"},
		},
		[]any{"pullRequest"},
	)
}

func listInputSchema() map[string]any {
	return objectSchema(
		map[string]any{
			"target":   nonEmptyStringSchema(),
			"resource": nonEmptyStringSchema(),
			"status": map[string]any{
				"type": "string",
				"enum": []any{"active", "paused", "completed", "blocked"},
			},
			"limit":  map[string]any{"type": "integer", "minimum": 1, "maximum": 100},
			"cursor": nonEmptyStringSchema(),
		},
		nil,
	)
}

func mutationInputSchema() map[string]any {
	schema := objectSchema(
		map[string]any{
			"watchId":     nonEmptyStringSchema(),
			"target":      nonEmptyStringSchema(),
			"pullRequest": nonEmptyStringSchema(),
		},
		nil,
	)
	schema["anyOf"] = []any{
		map[string]any{"required": []any{"watchId"}},
		map[string]any{"required": []any{"pullRequest"}},
	}
	return schema
}

func watchOutputSchema() map[string]any {
	return objectSchema(
		map[string]any{
			"watchId":     nonEmptyStringSchema(),
			"provider":    map[string]any{"type": "string", "const": Provider},
			"target":      nonEmptyStringSchema(),
			"pullRequest": nonEmptyStringSchema(),
			"resource":    nonEmptyStringSchema(),
			"status": map[string]any{
				"type": "string",
				"enum": []any{"active", "paused", "completed", "blocked"},
			},
			"events":    stringSetSchema(),
			"createdAt": map[string]any{"type": "string", "format": "date-time"},
			"updatedAt": map[string]any{"type": "string", "format": "date-time"},
		},
		[]any{"watchId"},
	)
}

func listOutputSchema() map[string]any {
	return objectSchema(
		map[string]any{
			"watches": map[string]any{
				"type":  "array",
				"items": watchOutputSchema(),
			},
			"limit":      map[string]any{"type": "integer", "minimum": 1, "maximum": 100},
			"cursor":     nonEmptyStringSchema(),
			"hasMore":    map[string]any{"type": "boolean"},
			"nextCursor": nonEmptyStringSchema(),
		},
		[]any{"watches"},
	)
}

func mutationOutputSchema(status string) map[string]any {
	return objectSchema(
		map[string]any{
			"watchId": nonEmptyStringSchema(),
			"status": map[string]any{
				"type":  "string",
				"const": status,
			},
		},
		[]any{"watchId", "status"},
	)
}

func objectSchema(properties map[string]any, required []any) map[string]any {
	schema := map[string]any{
		"$schema":              "https://json-schema.org/draft/2020-12/schema",
		"type":                 "object",
		"additionalProperties": false,
		"properties":           properties,
	}
	if len(required) > 0 {
		schema["required"] = required
	}
	return schema
}

func nonEmptyStringSchema() map[string]any {
	return map[string]any{"type": "string", "minLength": 1}
}

func stringSetSchema() map[string]any {
	return map[string]any{
		"type":        "array",
		"uniqueItems": true,
		"items":       nonEmptyStringSchema(),
	}
}
