package approvalir

import "fmt"

// DefinitionDecoder lowers a product-owned payload into neutral approval
// semantics. Product wire grammars and normalization remain in the decoder.
// Implementations must validate their result; product decoders should use
// DefinitionDecoderFunc so the neutral boundary enforces that invariant.
type DefinitionDecoder interface {
	DecodeApprovalDefinition(raw string) (*Definition, error)
}

// DefinitionDecoderFunc adapts a product decoder function and validates every
// definition before exposing it to L0 consumers.
type DefinitionDecoderFunc func(raw string) (*Definition, error)

type formulaValidatingDefinitionDecoder struct {
	decode           DefinitionDecoderFunc
	formulaValidator FormulaValidator
}

// NewFormulaValidatingDefinitionDecoder binds a product-owned approval grammar
// to the host's single formula-language validator. Formula criteria stay
// fail-closed when the validator is absent or rejects their source.
func NewFormulaValidatingDefinitionDecoder(decode DefinitionDecoderFunc, formulaValidator FormulaValidator) DefinitionDecoder {
	return formulaValidatingDefinitionDecoder{decode: decode, formulaValidator: formulaValidator}
}

// DecodeApprovalDefinition calls the product decoder and fails closed at the
// neutral contract boundary.
func (f DefinitionDecoderFunc) DecodeApprovalDefinition(raw string) (*Definition, error) {
	return decodeAndValidateDefinition(f, nil, raw)
}

func (d formulaValidatingDefinitionDecoder) DecodeApprovalDefinition(raw string) (*Definition, error) {
	if d.formulaValidator == nil {
		return nil, fmt.Errorf("approval formula validator is nil")
	}
	return decodeAndValidateDefinition(d.decode, d.formulaValidator, raw)
}

func decodeAndValidateDefinition(f DefinitionDecoderFunc, formulaValidator FormulaValidator, raw string) (*Definition, error) {
	if f == nil {
		return nil, fmt.Errorf("approval definition decoder is nil")
	}
	definition, err := f(raw)
	if err != nil {
		return nil, fmt.Errorf("decode approval definition: %w", err)
	}
	if definition == nil {
		return nil, fmt.Errorf("approval definition decoder returned nil")
	}
	if err := definition.validate(formulaValidator); err != nil {
		return nil, fmt.Errorf("decoded approval definition is invalid: %w", err)
	}
	return definition, nil
}
