package registry

import "github.com/tidbcloud/AgentTeam/internal/extension/spec"

// ActionPlan is the immutable server-only execution plan for one External
// Action. It combines the digest-pinned common Catalog fields with the
// kind-specific endpoint, auth slot, and HTTP binding. Values are detached from
// Registry state so a caller cannot mutate future invocations.
//
// Builtin executors do not have an HTTP ActionPlan; callers must use
// BuiltinExecutorFor for that kind.
type ActionPlan struct {
	DefinitionDigest  string
	Domain            string
	DefinitionVersion int
	ActionName        string
	Safety            spec.Safety
	InputSchema       map[string]any
	OutputSchema      map[string]any
	Endpoint          spec.Endpoint
	AuthRequirement   *spec.ActionAuthRequirement
	AuthProfile       *spec.AuthProfile
	Binding           spec.Binding
}

// ActionPlan returns a detached, digest-pinned HTTP execution plan for an
// External Action. It fails closed for an unknown digest/action, Builtin
// Definition, or any internal Catalog/binding/auth mismatch.
func (r *Registry) ActionPlan(digest, actionName string) (ActionPlan, bool) {
	if r == nil || digest == "" || actionName == "" {
		return ActionPlan{}, false
	}
	r.mu.RLock()
	defer r.mu.RUnlock()
	entry, ok := r.byDigest[digest]
	if !ok || entry.kind != External || entry.definition.Digest != digest {
		return ActionPlan{}, false
	}

	var catalogAction *DefinitionAction
	for i := range entry.definition.Actions {
		if entry.definition.Actions[i].Name == actionName {
			catalogAction = &entry.definition.Actions[i]
			break
		}
	}
	var bindingAction *ExternalBindingAction
	for i := range entry.binding.Actions {
		if entry.binding.Actions[i].Name == actionName {
			bindingAction = &entry.binding.Actions[i]
			break
		}
	}
	if catalogAction == nil || bindingAction == nil {
		return ActionPlan{}, false
	}

	var authProfile *spec.AuthProfile
	if bindingAction.Auth != nil {
		for i := range entry.binding.Auth.Profiles {
			profile := &entry.binding.Auth.Profiles[i]
			if profile.ID == bindingAction.Auth.Profile {
				cp := *profile
				authProfile = &cp
				break
			}
		}
		if authProfile == nil {
			return ActionPlan{}, false
		}
	}

	return ActionPlan{
		DefinitionDigest:  digest,
		Domain:            entry.definition.Domain,
		DefinitionVersion: entry.definition.Version,
		ActionName:        actionName,
		Safety:            catalogAction.Safety,
		InputSchema:       cloneSchema(catalogAction.InputSchema),
		OutputSchema:      cloneSchema(catalogAction.OutputSchema),
		Endpoint:          entry.binding.Endpoint,
		AuthRequirement:   cloneActionAuth(bindingAction.Auth),
		AuthProfile:       authProfile,
		Binding:           cloneBinding(bindingAction.Binding),
	}, true
}
