// Package arxiv registers the first-party arXiv Builtin Extension.
package arxiv

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

const (
	Domain       = "arxiv"
	Revision     = "arxiv-v1"
	ActionSearch = "search"
	ActionGet    = "get"
)

func Definition() registry.Definition {
	return registry.Definition{
		Domain:      Domain,
		Version:     1,
		Name:        "arXiv",
		Description: "Search arXiv papers and resolve PDF or source links.",
		Actions: []registry.DefinitionAction{
			{
				Name:         ActionSearch,
				Summary:      "Search arXiv",
				Description:  "Search the public arXiv Atom API with native query syntax.",
				Safety:       readSafety(),
				InputSchema:  searchInputSchema(),
				OutputSchema: searchOutputSchema(),
				Example: map[string]any{
					"query":  "au:del_maestro AND ti:checkerboard",
					"limit":  10,
					"sortBy": "submittedDate",
				},
			},
			{
				Name:         ActionGet,
				Summary:      "Get an arXiv paper",
				Description:  "Resolve one modern or legacy arXiv identifier.",
				Safety:       readSafety(),
				InputSchema:  paperIDInputSchema(),
				OutputSchema: paperResultSchema(),
				Example: map[string]any{
					"id": "1605.08386v1",
				},
			},
		},
	}
}

func readSafety() spec.Safety {
	return spec.Safety{
		Class:       "read",
		Idempotent:  true,
		Destructive: false,
	}
}

func searchInputSchema() map[string]any {
	return map[string]any{
		"$schema":              "https://json-schema.org/draft/2020-12/schema",
		"type":                 "object",
		"additionalProperties": false,
		"anyOf": []any{
			map[string]any{"required": []any{"query"}},
			map[string]any{
				"required": []any{"idList"},
				"properties": map[string]any{
					"idList": map[string]any{"minItems": 1},
				},
			},
		},
		"properties": map[string]any{
			"query": map[string]any{
				"type":      "string",
				"minLength": 1,
				"maxLength": 2048,
			},
			"idList": map[string]any{
				"type":     "array",
				"maxItems": 100,
				"items":    paperIDSchema(),
			},
			"offset": map[string]any{
				"type":    "integer",
				"minimum": 0,
				"maximum": 29999,
			},
			"limit": map[string]any{
				"type":    "integer",
				"minimum": 1,
				"maximum": 20,
			},
			"sortBy": map[string]any{
				"type": "string",
				"enum": []any{
					"relevance",
					"lastUpdatedDate",
					"submittedDate",
				},
			},
			"sortOrder": map[string]any{
				"type": "string",
				"enum": []any{"ascending", "descending"},
			},
		},
	}
}

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

func paperIDSchema() map[string]any {
	return map[string]any{
		"type":      "string",
		"minLength": 9,
		"maxLength": 64,
		"pattern": `^(?:[0-9]{4}\.[0-9]{4,5}|` +
			`[A-Za-z0-9.-]+/[0-9]{7})(?:v[1-9][0-9]*)?$`,
	}
}

func searchOutputSchema() map[string]any {
	return map[string]any{
		"$schema":              "https://json-schema.org/draft/2020-12/schema",
		"type":                 "object",
		"additionalProperties": false,
		"required": []any{
			"papers",
			"totalResults",
			"offset",
			"returned",
			"hasMore",
		},
		"properties": map[string]any{
			"papers": map[string]any{
				"type":     "array",
				"maxItems": 20,
				"items":    paperSchema(),
			},
			"totalResults": nonNegativeIntegerSchema(),
			"offset":       nonNegativeIntegerSchema(),
			"returned":     nonNegativeIntegerSchema(),
			"hasMore":      map[string]any{"type": "boolean"},
			"nextOffset":   nonNegativeIntegerSchema(),
		},
	}
}

func paperResultSchema() map[string]any {
	return map[string]any{
		"$schema":              "https://json-schema.org/draft/2020-12/schema",
		"type":                 "object",
		"additionalProperties": false,
		"required":             []any{"paper"},
		"properties": map[string]any{
			"paper": paperSchema(),
		},
	}
}

func paperSchema() map[string]any {
	stringSchema := map[string]any{"type": "string"}
	uriSchema := map[string]any{"type": "string", "format": "uri"}
	authorSchema := map[string]any{
		"type":                 "object",
		"additionalProperties": false,
		"required":             []any{"name", "affiliations"},
		"properties": map[string]any{
			"name": stringSchema,
			"affiliations": map[string]any{
				"type":  "array",
				"items": stringSchema,
			},
		},
	}
	linkSchema := map[string]any{
		"type":                 "object",
		"additionalProperties": false,
		"required":             []any{"href"},
		"properties": map[string]any{
			"href":        uriSchema,
			"title":       stringSchema,
			"rel":         stringSchema,
			"contentType": stringSchema,
		},
	}
	return map[string]any{
		"type":                 "object",
		"additionalProperties": false,
		"required": []any{
			"id",
			"entryUrl",
			"publishedAt",
			"updatedAt",
			"title",
			"authors",
			"abstract",
			"primaryCategory",
			"categories",
			"links",
		},
		"properties": map[string]any{
			"id":              paperIDSchema(),
			"entryUrl":        uriSchema,
			"publishedAt":     map[string]any{"type": "string", "format": "date-time"},
			"updatedAt":       map[string]any{"type": "string", "format": "date-time"},
			"title":           stringSchema,
			"authors":         map[string]any{"type": "array", "items": authorSchema},
			"abstract":        stringSchema,
			"comment":         stringSchema,
			"journalRef":      stringSchema,
			"doi":             stringSchema,
			"primaryCategory": stringSchema,
			"categories":      map[string]any{"type": "array", "items": stringSchema},
			"links":           map[string]any{"type": "array", "items": linkSchema},
			"pdfUrl":          uriSchema,
			"sourceUrl":       uriSchema,
		},
	}
}

func nonNegativeIntegerSchema() map[string]any {
	return map[string]any{"type": "integer", "minimum": 0}
}
