package invocationmanage

import (
	"errors"

	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
)

type ErrorCode string

const (
	ErrorCodeInvalidRequest         ErrorCode = "invocation_invalid_request"
	ErrorCodeNotFound               ErrorCode = "invocation_not_found"
	ErrorCodePlanVersionUnavailable ErrorCode = "invocation_plan_version_unavailable"
	ErrorCodePrincipalUnavailable   ErrorCode = "invocation_principal_unavailable"
	ErrorCodeIdempotencyConflict    ErrorCode = "invocation_idempotency_conflict"
	ErrorCodeInputInvalid           ErrorCode = "invocation_input_invalid"
	ErrorCodeForbidden              ErrorCode = "invocation_forbidden"
	ErrorCodeConflict               ErrorCode = "invocation_conflict"
)

type RequestError struct {
	Kind    error
	Code    ErrorCode
	Message string
	Details any
	Cause   error
}

func (err RequestError) Error() string { return err.Message }

// Unwrap returns the declared store kind only. The declared Kind is
// authoritative for public status/code classification: the internal Cause is
// preserved separately (InternalCause) for logs and structured logging and
// never participates in the errors.Is/As graph consumed by publicerr, so an
// internal cause that itself carries a store sentinel can never override the
// declared kind.
func (err RequestError) Unwrap() error { return err.Kind }

// InternalCause returns the originating repository error retained exclusively
// for logs and wrapping, or nil. It is deliberately not part of the Unwrap
// chain.
func (err RequestError) InternalCause() error { return err.Cause }

// WorkflowPublicError implements publicerr.DomainError so the centralized
// Workflow error classifier can extract the stable code and structured details
// without importing this domain package.
func (err RequestError) WorkflowPublicError() (string, any) {
	return string(err.Code), err.Details
}

func ErrorDetails(err error) (ErrorCode, any, bool) {
	var requestError RequestError
	if !errors.As(err, &requestError) {
		return "", nil, false
	}
	return requestError.Code, requestError.Details, true
}

func invalidRequest(message string) error {
	return RequestError{Kind: storeerr.ErrBadRequest, Code: ErrorCodeInvalidRequest, Message: message}
}

func inputInvalid(code string, path string, message string) error {
	return RequestError{
		Kind: storeerr.ErrUnprocessable, Code: ErrorCodeInputInvalid, Message: message,
		Details: map[string]any{"diagnostics": []Diagnostic{{Severity: "error", Code: code, Path: path, Message: message}}},
	}
}

// Diagnostic is the stable path-aware shape shared by HTTP and model-facing
// transports. Invocation validation currently emits one authoritative Plan
// diagnostic at a time.
type Diagnostic struct {
	Severity string `json:"severity"`
	Code     string `json:"code"`
	Path     string `json:"path"`
	Message  string `json:"message"`
}
