package analytics

import (
	"errors"
	"fmt"
)

const (
	// maxCompiledFormulaSQLBytes bounds every recursively compiled formula SQL
	// fragment. The composed release corpus measured 4,219 bytes at its largest;
	// 64 KiB leaves more than 15x headroom while stopping a duplicating parent
	// emitter before it can amplify an already-oversized child.
	maxCompiledFormulaSQLBytes = 64 << 10

	// maxFormulaViewDDLBytes bounds the complete CREATE VIEW statement assembled
	// by DSLViewBuilder. The same corpus measured 37,478 bytes at its largest, so
	// 1 MiB leaves more than 27x headroom for cumulative view growth.
	maxFormulaViewDDLBytes = 1 << 20
)

// ErrFormulaSQLOutputTooLarge identifies formula SQL that exceeds a compiler or
// view-builder output bound.
var ErrFormulaSQLOutputTooLarge = errors.New("formula SQL output too large")

// FormulaSQLOutputTooLargeError reports a bounded, non-SQL description of an
// oversized compiler or view-builder result.
type FormulaSQLOutputTooLargeError struct {
	Scope       string
	ActualBytes int
	MaxBytes    int
}

func (e *FormulaSQLOutputTooLargeError) Error() string {
	return fmt.Sprintf(
		"%s: %s emitted %d bytes (maximum %d)",
		ErrFormulaSQLOutputTooLarge,
		e.Scope,
		e.ActualBytes,
		e.MaxBytes,
	)
}

func (e *FormulaSQLOutputTooLargeError) Unwrap() error {
	return ErrFormulaSQLOutputTooLarge
}

func checkFormulaSQLOutputSize(scope string, actual, max int) error {
	if actual <= max {
		return nil
	}
	if scope == "" {
		scope = "formula SQL"
	}
	return &FormulaSQLOutputTooLargeError{
		Scope:       scope,
		ActualBytes: actual,
		MaxBytes:    max,
	}
}
