package client

import "time"

// Capability is THE wire shape for a Hexis capability.
//
// There is exactly one definition of it, here, and every producer in this
// repository serializes through it: the HTTP handler (GET/POST
// /api/v1/capabilities, GET /api/v1/capabilities/{id}), the MCP adapter
// (hexis.list_capabilities), and this client's decode path. It lives in
// pkg/client rather than internal/ so that external consumers get the shape
// without vendoring internal packages; internal/wire holds the
// domain.Capability -> Capability conversion.
//
// Compatibility note — `id` and `capability_id` are BOTH emitted, deliberately.
// They always carry the same value. Maven's vendored consumer decodes `id`
// (cmd/mavend/voice.go matches on Capability.ID); the ECOSYSTEM-SPEC.md §4.1
// schema and the rest of the Hexis API name the column `capability_id`. Hexis
// is mid-rollout of bearer auth on /api/v1/, which is already one breaking
// change for that consumer; dropping either alias here would stack a second,
// silent one on top. Both stay until every consumer is confirmed to read
// `capability_id`, at which point `id` can be removed in a deliberate,
// announced change. Do not "clean this up" incidentally.
type Capability struct {
	// CapabilityID is the canonical field (ECOSYSTEM-SPEC.md §4.1).
	CapabilityID string `json:"capability_id"`
	// ID is a deprecated alias for CapabilityID, kept for wire compatibility.
	// Always identical to CapabilityID. Prefer CapabilityID in new code.
	ID string `json:"id"`

	Name                string   `json:"name"`
	Description         string   `json:"description,omitempty"`
	TargetTypes         []string `json:"target_types"`
	TargetEntityID      string   `json:"target_entity_id,omitempty"`
	Provider            string   `json:"provider"`
	Operation           string   `json:"operation"`
	Risk                string   `json:"risk,omitempty"`
	ReadOnly            bool     `json:"read_only"`
	ExpectedSideEffects string   `json:"expected_side_effects,omitempty"`

	// RequiresConfirmation and Enabled are server-derived from the risk tier
	// and are never settable by a caller. listCapabilities used to omit both,
	// which left clients unable to tell a callable capability from one that
	// would be rejected with 403; the unified shape always carries them.
	RequiresConfirmation bool `json:"requires_confirmation"`
	Enabled              bool `json:"enabled"`
	TimeoutSeconds       int  `json:"timeout_seconds,omitempty"`

	Attributes map[string]any `json:"attributes,omitempty"`
	CreatedAt  time.Time      `json:"created_at,omitempty"`
	UpdatedAt  time.Time      `json:"updated_at,omitempty"`
	Version    int64          `json:"version,omitempty"`
}

// EffectiveID returns the capability ID, tolerating a peer that sends only one
// of the two aliases.
func (c Capability) EffectiveID() string {
	if c.CapabilityID != "" {
		return c.CapabilityID
	}
	return c.ID
}
