package soql

import (
	"fmt"

	apperrors "github.com/nexuscrm/shared/pkg/errors"
)

// Module-local error types for the standalone SOQL dialect module.
//
// This compatibility module is seal-clean: it uses the stdlib-only L1 query
// codec plus github.com/nexuscrm/shared adapters and must not depend on
// github.com/nexuscrm/backend. Resolver-only internal error vocabulary remains
// here while the transitional dialect still consumes shared request types.
//
// The .Error() text of these types is byte-identical to the corresponding
// backend/pkg/errors.ValidationError / InternalError so that the v63 wire
// shape emitted by the REST consumers (query / tooling / bulk handlers) does
// not change when the parser is read through this module instead of the
// in-tree package. Boundary classification (internal vs business) is carried
// by the neutral, transport-free shared marker appErrors.InternalConditioner —
// the only error fact shared owns.

// validationError mirrors backend/pkg/errors.ValidationError.Error() exactly.
// It is a plain business/validation failure and is intentionally NOT marked as
// an internal condition.
type validationError struct {
	Field   string
	Message string
}

func (e *validationError) Error() string {
	if e.Field != "" {
		return fmt.Sprintf("validation error on field '%s': %s", e.Field, e.Message)
	}
	return fmt.Sprintf("validation error: %s", e.Message)
}

// newValidationError constructs a SOQL parse/validation error with the same
// text contract as backend/pkg/errors.NewValidationError.
func newValidationError(field, message string) *validationError {
	return &validationError{Field: field, Message: message}
}

// internalError mirrors backend/pkg/errors.InternalError.Error() exactly and
// participates in the shared neutral internal-error classifier so that a
// genuine infrastructure failure surfaced from the resolver is not misreported
// as a user-facing 4xx by the consuming handler's RespondError.
type internalError struct {
	Message string
	Cause   error
}

func (e *internalError) Error() string {
	if e.Cause != nil {
		return fmt.Sprintf("internal error: %s (caused by: %v)", e.Message, e.Cause)
	}
	return fmt.Sprintf("internal error: %s", e.Message)
}

// Unwrap exposes the wrapped cause so errors.As/Is traverse the chain — this
// preserves the v63 contract where an inner PermissionError / NotFoundError /
// InternalError from a semi-join subquery is classified by the handler rather
// than collapsed into MALFORMED_QUERY.
func (e *internalError) Unwrap() error {
	return e.Cause
}

// InternalCondition satisfies appErrors.InternalConditioner: an internalError
// is always an internal/infrastructure failure.
func (e *internalError) InternalCondition() bool {
	return true
}

// compile-time proof that internalError implements the shared neutral marker.
var _ apperrors.InternalConditioner = (*internalError)(nil)

// newInternalError constructs a SOQL internal error with the same text contract
// as backend/pkg/errors.NewInternalError.
func newInternalError(message string, cause error) *internalError {
	return &internalError{Message: message, Cause: cause}
}
