package runtime

import (
	"errors"
	"fmt"
)

// ErrRuntimeConnectionUnavailable classifies a missing, ambiguous, or invalid
// local App connection without treating dependency failures as credentials.
var ErrRuntimeConnectionUnavailable = errors.New(
	"search engine runtime connection unavailable",
)

// ErrorCode is the stable classification consumed by Builtin executors.
type ErrorCode string

const (
	ErrorValidation              ErrorCode = "validation"
	ErrorProviderAuthUnavailable ErrorCode = "provider_auth_unavailable"
	ErrorRateLimited             ErrorCode = "rate_limited"
	ErrorUpstreamFailure         ErrorCode = "upstream_failure"
)

// Error contains a sanitized public message and an optional internal cause.
type Error struct {
	Code    ErrorCode
	Message string
	Cause   error
}

func (err *Error) Error() string {
	if err == nil {
		return ""
	}
	return err.Message
}

func (err *Error) Unwrap() error {
	if err == nil {
		return nil
	}
	return err.Cause
}

func searchError(code ErrorCode, message string, cause error) error {
	return &Error{Code: code, Message: message, Cause: cause}
}

// CodeOf returns the stable search error code or an empty value.
func CodeOf(err error) ErrorCode {
	var typed *Error
	if errors.As(err, &typed) && typed != nil {
		return typed.Code
	}
	return ""
}

type runtimeConnectionUnavailableError struct {
	cause error
}

func (err runtimeConnectionUnavailableError) Error() string {
	return ErrRuntimeConnectionUnavailable.Error()
}

func (err runtimeConnectionUnavailableError) Unwrap() []error {
	return []error{ErrRuntimeConnectionUnavailable, err.cause}
}

// RuntimeConnectionUnavailable marks an expected local connection failure.
// The rendered error remains stable and never exposes the persistence cause.
func RuntimeConnectionUnavailable(cause error) error {
	if cause == nil {
		cause = ErrRuntimeConnectionUnavailable
	}
	return runtimeConnectionUnavailableError{cause: cause}
}

func internalError(label string, err error) error {
	if err == nil {
		err = errors.New(label)
	}
	return fmt.Errorf("%s: %w", label, err)
}
