// Package hackernews registers the Hacker News Builtin Extension ported from
// OpenConnector (baseline 0484cac): connectionless reads over the two public
// Hacker News APIs across the full 14-action upstream catalog. Item, user,
// update, and story-feed Actions pass the Firebase responses through; the
// Algolia-backed search Actions pass the search envelopes through;
// get-item-with-id assembles a bounded nested comment tree. Outputs are bounded
// provider passthrough objects.
//
// One deliberate AgentTeam-side divergence: upstream bounds get-item-with-id only by
// the per-call max_depth/max_children parameters, which still permits an
// unbounded fan-out of recursive item fetches (100^10 at the parameter maxima).
// The port adds an aggregate per-invocation assembly budget — a hard cap on
// total item fetches and total assembled tree nodes that no parameter can
// widen — and reports the cut as a top-level budget_exhausted flag plus the
// per-node children_truncated flag. Upstream has no such budget or flag. On
// top of those count caps, three cumulative budgets — upstream bytes read
// (charged on the raw wire size, so whitespace padding cannot evade the cap),
// marshaled output size, and wall clock — fail the invocation outright with a
// stable classified error, so a hostile or buggy fixed origin cannot amortize
// unbounded reads, payload size, or time inside count-legal fetches.
//
// Synthesized outputs never violate their declared schemas: story feeds and
// the max-item counter reject null or non-conforming bodies, Algolia envelopes
// must be JSON objects, tree nodes are admitted only when they can satisfy the
// declared node contract (safe-integral id, declared type) with copied fields
// type-guarded, and passthrough fields the origins really send as null (user
// about, item strings) are declared nullable. Comment text truncation counts
// UTF-16 code units like the baseline's JavaScript slice, never splitting a
// surrogate pair.
package hackernews

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

const (
	// Domain is the Extension domain.
	Domain = "hackernews"
	// Revision is the implementation identity folded into the runtime digest.
	// v1 serves the full upstream catalog with per-invocation tree budgets
	// (fetches, nodes, raw wire bytes, output size, wall clock), charges the
	// byte budget on the raw wire size, keeps deadline provenance honest,
	// guards the user summary's nullable about, and unifies the item-ID
	// acceptance set between schema and handler.
	Revision = "hackernews-rest-v1"
	// FirebaseBaseURL is the fixed Hacker News Firebase API origin serving
	// item, user, maxitem, and updates reads.
	FirebaseBaseURL = "https://hacker-news.firebaseio.com/v0"
	// AlgoliaBaseURL is the fixed Hacker News Algolia search origin serving
	// the search and search_by_date reads.
	AlgoliaBaseURL = "https://hn.algolia.com/api/v1"
)

// Extension composes the Hacker News Builtin. Both public origins need no
// credential, so the Extension is connectionless: the zero AuthSpec keeps
// AuthNone with no fields and no live validator, matching the bootstrap
// no-auth contract, and the executor dispatches on the package Firebase
// client.
func Extension() (extension.Extension, error) {
	executor := runner.NewRESTExecutor(Domain, firebaseClient, nil, Handlers())
	return extension.Extension{
		Definition: Definition(),
		Implementation: runner.Implementation{
			Executor:         executor,
			Revision:         Revision,
			ConnectionPolicy: registry.ConnectionNone,
			Auth:             runner.AuthSpec{},
		},
		Distribution: extension.Distribution{
			AppID:          "app_hackernews",
			AppSlug:        "hackernews",
			DefaultName:    Domain,
			DefaultEnabled: true,
			IconURL:        "/app-icons/hackernews.svg",
		},
	}, nil
}
