package eventstore

import (
	"crypto/sha256"
	"fmt"
	"slices"
	"strings"
	"time"
)

type (
	// FilterEventTypeString represents an event type identifier used in filter criteria.
	FilterEventTypeString = string

	// FilterKeyString represents a JSON key used in filter predicate matching.
	FilterKeyString = string

	// FilterValString represents a JSON value used in filter predicate matching.
	FilterValString = string
)

/***** Filter *****/

// Filter represents a complete event filter with FilterItems and optional time or sequence boundaries.
// Multiple FilterItems are combined with OR logic, while predicates within items follow
// configurable AND/OR logic based on AllPredicatesMustMatch.
type Filter struct {
	items                    []FilterItem
	occurredFrom             time.Time
	occurredUntil            time.Time
	sequenceNumberHigherThan uint
}

// ReopenForSequenceFiltering attempts to reopen this filter for sequence number filtering.
// Returns either SequenceFilteringCapable (if no time boundaries are set) or
// SequenceFilteringIncompatible (if time boundaries conflict).
// This provides compile-time safety - you can only call WithSequenceNumberHigherThan
// on the returned interface if the filter is compatible.
func (f Filter) ReopenForSequenceFiltering() interface{} {
	if !f.occurredFrom.IsZero() || !f.occurredUntil.IsZero() {
		return &incompatibleFilterState{
			reason: "cannot add sequence filtering: time boundaries already present",
		}
	}
	return &sequenceFilterBuilder{baseFilter: f}
}

// Items returns the collection of FilterItems that define the filter criteria.
func (f Filter) Items() []FilterItem {
	return f.items
}

// OccurredFrom returns the lower time boundary for event filtering (inclusive).
func (f Filter) OccurredFrom() time.Time {
	return f.occurredFrom
}

// OccurredUntil returns the upper time boundary for event filtering (inclusive).
func (f Filter) OccurredUntil() time.Time {
	return f.occurredUntil
}

// SequenceNumberHigherThan returns the minimum sequence number for event filtering (exclusive).
func (f Filter) SequenceNumberHigherThan() uint {
	return f.sequenceNumberHigherThan
}

// Hash returns a deterministic SHA256 hash of the filter for snapshot identification.
// The hash includes all filter components: items, time boundaries, and sequence boundaries.
func (f Filter) Hash() string {
	hasher := sha256.New()
	hasher.Write([]byte(f.Serialize()))
	return fmt.Sprintf("sha256:%x", hasher.Sum(nil))
}

// Serialize creates a deterministic string representation of the filter for hashing.
// The serialization includes all filter components in a consistent order.
func (f Filter) Serialize() string {
	parts := make([]string, 0, len(f.items)+3) // Pre-allocate for items and potential time/sequence boundaries

	// Serialize filter items (already sorted by the builder)
	for i, item := range f.items {
		itemParts := []string{fmt.Sprintf("item:%d", i)}

		// Add event types (already sorted)
		if len(item.eventTypes) > 0 {
			itemParts = append(itemParts, "event_types:"+strings.Join(item.eventTypes, ","))
		}

		// Add predicates (already sorted by key)
		if len(item.predicates) > 0 {
			var predicateStrings []string
			for _, predicate := range item.predicates {
				predicateStrings = append(predicateStrings, fmt.Sprintf("%s=%s", predicate.key, predicate.val))
			}

			itemParts = append(itemParts, "predicates:"+strings.Join(predicateStrings, ","))
		}

		// Add predicate logic
		if item.allPredicatesMustMatch {
			itemParts = append(itemParts, "predicate_logic:AND")
		} else {
			itemParts = append(itemParts, "predicate_logic:OR")
		}

		parts = append(parts, strings.Join(itemParts, "|"))
	}

	// Add time boundaries
	if !f.occurredFrom.IsZero() {
		parts = append(parts, "occurred_from:"+f.occurredFrom.Format(time.RFC3339Nano))
	}
	if !f.occurredUntil.IsZero() {
		parts = append(parts, "occurred_until:"+f.occurredUntil.Format(time.RFC3339Nano))
	}

	// Add the sequence boundary
	if f.sequenceNumberHigherThan > 0 {
		parts = append(parts, fmt.Sprintf("sequence_higher_than:%d", f.sequenceNumberHigherThan))
	}

	return strings.Join(parts, "||")
}

/***** FilterItem *****/

// FilterItem represents a single filter condition combining event types and JSON predicates.
// Event types are always combined with OR logic, while predicates follow AND / OR logic
// based on the AllPredicatesMustMatch flag.
type FilterItem struct {
	eventTypes             []FilterEventTypeString
	predicates             []FilterPredicate
	allPredicatesMustMatch bool
}

// EventTypes returns the event type identifiers for this filter item.
func (fi FilterItem) EventTypes() []FilterEventTypeString {
	return fi.eventTypes
}

// Predicates returns the JSON predicates for this filter item.
func (fi FilterItem) Predicates() []FilterPredicate {
	return fi.predicates
}

// AllPredicatesMustMatch returns true if all predicates must match (AND logic),
// false if any predicate can match (OR logic).
func (fi FilterItem) AllPredicatesMustMatch() bool {
	return fi.allPredicatesMustMatch
}

/***** FilterPredicate *****/

// FilterPredicate represents a key-value pair for matching JSON payload fields.
type FilterPredicate struct {
	key FilterKeyString
	val FilterValString
}

// P creates a new FilterPredicate with the specified key and value.
func P(key FilterKeyString, val FilterValString) FilterPredicate {
	return FilterPredicate{key: key, val: val}
}

// Key returns the JSON key for this predicate.
func (fp FilterPredicate) Key() FilterKeyString {
	return fp.key
}

// Val returns the JSON value for this predicate.
func (fp FilterPredicate) Val() FilterValString {
	return fp.val
}

/***** FilterBuilder *****/

// FilterBuilder builds generic event filters for database-specific query implementations.
// It enforces useful filter combinations for event-sourced workflows, supporting event types,
// JSON payload predicates, and time ranges. Complex combinations are supported through multiple
// FilterItems with OR logic between items and configurable AND/OR logic within items.
type FilterBuilder interface {
	// Matching starts a new FilterItem.
	Matching() EmptyFilterItemBuilder

	// MatchingAnyEvent directly creates an empty Filter.
	// WARNING: This returns ALL events and should not be used in production.
	MatchingAnyEvent() Filter

	// OccurredFrom sets the lower boundary for occurredAt (including this timestamp) for the whole Filter.
	OccurredFrom(occurredAtFrom time.Time) CompletedFilterItemBuilderWithOccurredFrom

	// OccurredUntil sets the upper boundary for occurredAt (including this timestamp) for the whole Filter.
	//
	// Currently, there is NO check if OccurredUntil is later than OccurredFrom!
	OccurredUntil(occurredAtUntil time.Time) CompletedFilterItemBuilderWithOccurredUntil

	// WithSequenceNumberHigherThan sets the sequence number boundary (exclusive) for the whole Filter.
	// This makes time boundaries unavailable (mutually exclusive).
	WithSequenceNumberHigherThan(sequenceNumber uint) CompletedFilterItemBuilderWithSequenceNumber
}

// EmptyFilterItemBuilder represents the initial state when starting a new FilterItem.
// At this stage, you must add either event types or predicates to proceed.
type EmptyFilterItemBuilder interface {
	// AnyEventTypeOf adds one or multiple EventTypes to the current FilterItem.
	//
	// It sanitizes the input:
	//	- removing empty EventTypes ("")
	//	- sorting the EventTypes
	//	- removing duplicate EventTypes
	AnyEventTypeOf(eventType FilterEventTypeString, eventTypes ...FilterEventTypeString) FilterItemBuilderLackingPredicates

	// AnyPredicateOf adds one or multiple FilterPredicate(s) to the current FilterItem.
	//
	// It sanitizes the input:
	//	- removing empty/partial FilterPredicate(s) (key or val is "")
	//	- sorting the FilterPredicate(s)
	//	- removing duplicate FilterPredicate(s)
	AnyPredicateOf(predicate FilterPredicate, predicates ...FilterPredicate) FilterItemBuilderLackingEventTypes

	// AllPredicatesOf adds one or multiple FilterPredicate(s) to the current FilterItem expecting ALL predicates to match.
	//
	// It sanitizes the input:
	//	- removing empty/partial FilterPredicate(s) (key or val is "")
	//	- sorting the FilterPredicate(s)
	//	- removing duplicate FilterPredicate(s)
	AllPredicatesOf(predicate FilterPredicate, predicates ...FilterPredicate) FilterItemBuilderLackingEventTypes
}

// FilterItemBuilderLackingPredicates represents a FilterItem with event types but no predicates yet.
// You can optionally add predicates, set time boundaries, add more items, or finalize the filter.
type FilterItemBuilderLackingPredicates interface {
	// AndAnyPredicateOf adds one or multiple FilterPredicate(s) to the current FilterItem expecting ANY predicate to match.
	//
	// It sanitizes the input:
	//	- removing empty/partial FilterPredicate(s) (key or val is "")
	//	- sorting the FilterPredicate(s)
	//	- removing duplicate FilterPredicate(s)
	AndAnyPredicateOf(predicate FilterPredicate, predicates ...FilterPredicate) CompletedFilterItemBuilder

	// AndAllPredicatesOf adds one or multiple FilterPredicate(s) to the current FilterItem expecting ALL predicates to match.
	//
	// It sanitizes the input:
	//	- removing empty/partial FilterPredicate(s) (key or val is "")
	//	- sorting the FilterPredicate(s)
	//	- removing duplicate FilterPredicate(s)
	AndAllPredicatesOf(predicate FilterPredicate, predicates ...FilterPredicate) CompletedFilterItemBuilder

	// OccurredFrom sets the lower boundary for occurredAt (including this timestamp) for the whole Filter.
	OccurredFrom(occurredAtFrom time.Time) CompletedFilterItemBuilderWithOccurredFrom

	// OccurredUntil sets the upper boundary for occurredAt (including this timestamp) for the whole Filter.
	//
	// Currently, there is NO check if OccurredUntil is later than OccurredFrom!
	OccurredUntil(occurredAtUntil time.Time) CompletedFilterItemBuilderWithOccurredUntil

	// WithSequenceNumberHigherThan sets the sequence number boundary (exclusive) for the whole Filter.
	// This makes time boundaries unavailable (mutually exclusive).
	WithSequenceNumberHigherThan(sequenceNumber uint) CompletedFilterItemBuilderWithSequenceNumber

	// OrMatching finalizes the current FilterItem and starts a new one.
	OrMatching() EmptyFilterItemBuilder

	// Finalize returns the Filter once it has at least one FilterItem with at least one EventType OR one Predicate.
	Finalize() Filter
}

// FilterItemBuilderLackingEventTypes represents a FilterItem with predicates but no event types yet.
// You can optionally add event types, set time boundaries, add more items, or finalize the filter.
type FilterItemBuilderLackingEventTypes interface {
	// AndAnyEventTypeOf adds one or multiple EventTypes to the current FilterItem.
	//
	// It sanitizes the input:
	//	- removing empty EventTypes ("")
	//	- sorting the EventTypes
	//	- removing duplicate EventTypes
	AndAnyEventTypeOf(eventType FilterEventTypeString, eventTypes ...FilterEventTypeString) CompletedFilterItemBuilder

	// OccurredFrom sets the lower boundary for occurredAt (including this timestamp) for the whole Filter.
	OccurredFrom(occurredAtFrom time.Time) CompletedFilterItemBuilderWithOccurredFrom

	// OccurredUntil sets the upper boundary for occurredAt (including this timestamp) for the whole Filter.
	//
	// Currently, there is NO check if OccurredUntil is later than OccurredFrom!
	OccurredUntil(occurredAtUntil time.Time) CompletedFilterItemBuilderWithOccurredUntil

	// WithSequenceNumberHigherThan sets the sequence number boundary (exclusive) for the whole Filter.
	// This makes time boundaries unavailable (mutually exclusive).
	WithSequenceNumberHigherThan(sequenceNumber uint) CompletedFilterItemBuilderWithSequenceNumber

	// OrMatching finalizes the current FilterItem and starts a new one.
	OrMatching() EmptyFilterItemBuilder

	// Finalize returns the Filter once it has at least one FilterItem with at least one EventType OR one Predicate.
	Finalize() Filter
}

// CompletedFilterItemBuilder represents a FilterItem with both event types and predicates.
// You can set time boundaries, add more items, or finalize the filter.
type CompletedFilterItemBuilder interface {
	// OccurredFrom sets the lower boundary for occurredAt (including this timestamp) for the whole Filter.
	OccurredFrom(occurredAtFrom time.Time) CompletedFilterItemBuilderWithOccurredFrom

	// OccurredUntil sets the upper boundary for occurredAt (including this timestamp) for the whole Filter.
	//
	// Currently, there is NO check if OccurredUntil is later than OccurredFrom!
	OccurredUntil(occurredAtUntil time.Time) CompletedFilterItemBuilderWithOccurredUntil

	// WithSequenceNumberHigherThan sets the sequence number boundary (exclusive) for the whole Filter.
	// This makes time boundaries unavailable (mutually exclusive).
	WithSequenceNumberHigherThan(sequenceNumber uint) CompletedFilterItemBuilderWithSequenceNumber

	// OrMatching finalizes the current FilterItem and starts a new one.
	OrMatching() EmptyFilterItemBuilder

	// Finalize returns the Filter once it has at least one FilterItem with at least one EventType OR one Predicate.
	Finalize() Filter
}

// CompletedFilterItemBuilderWithOccurredFrom represents a completed FilterItem with a lower time boundary set.
// You can optionally add an upper time boundary or finalize the filter.
type CompletedFilterItemBuilderWithOccurredFrom interface {
	// AndOccurredUntil sets the upper boundary for occurredAt (including this timestamp) for the whole Filter.
	//
	// Currently, there is NO check if AndOccurredUntil is later than OccurredFrom!
	AndOccurredUntil(occurredAtUntil time.Time) CompletedFilterItemBuilderWithOccurredFromToUntil

	// Finalize returns the Filter once it has at least one FilterItem with at least one EventType OR one Predicate.
	Finalize() Filter
}

// CompletedFilterItemBuilderWithOccurredUntil represents a completed FilterItem with an upper time boundary set.
// You can only finalize the filter at this stage.
type CompletedFilterItemBuilderWithOccurredUntil interface {
	// Finalize returns the Filter once it has at least one FilterItem with at least one EventType OR one Predicate.
	Finalize() Filter
}

// CompletedFilterItemBuilderWithOccurredFromToUntil represents a completed FilterItem with both time boundaries set.
// You can only finalize the filter at this stage.
type CompletedFilterItemBuilderWithOccurredFromToUntil interface {
	// Finalize returns the Filter once it has at least one FilterItem with at least one EventType OR one Predicate.
	Finalize() Filter
}

// CompletedFilterItemBuilderWithSequenceNumber represents a completed FilterItem with a sequence boundary set.
// You can only finalize the filter at this stage.
type CompletedFilterItemBuilderWithSequenceNumber interface {
	// Finalize returns the Filter once it has at least one FilterItem with at least one EventType OR one Predicate.
	Finalize() Filter
}

// filterBuilder implements all the interfaces of FilterBuilder and provides the concrete
// implementation for building event filters through a fluent interface.
type filterBuilder struct {
	filter            Filter
	currentFilterItem FilterItem
}

// BuildEventFilter creates a FilterBuilder which must eventually be finalized with Finalize() or MatchingAnyEvent().
// Note: MatchingAnyEvent() returns ALL events and should not be used in production.
func BuildEventFilter() FilterBuilder {
	return filterBuilder{}
}

// Matching starts a new FilterItem.
func (fb filterBuilder) Matching() EmptyFilterItemBuilder {
	fb.currentFilterItem = FilterItem{}

	return fb
}

// AnyEventTypeOf adds one or multiple EventTypes to the current FilterItem expecting ANY EventType to match.
//
// It sanitizes the input:
//   - removing empty EventTypes ("")
//   - sorting the EventTypes
//   - removing duplicate EventTypes
func (fb filterBuilder) AnyEventTypeOf(
	eventType FilterEventTypeString,
	eventTypes ...FilterEventTypeString,
) FilterItemBuilderLackingPredicates {

	fb.currentFilterItem.eventTypes = append(
		fb.currentFilterItem.eventTypes,
		fb.sanitizeEventTypes(eventType, eventTypes...)...,
	)

	return fb
}

// AndAnyEventTypeOf adds one or multiple EventTypes to the current FilterItem expecting ANY EventType to match.
//
// It sanitizes the input:
//   - removing empty EventTypes ("")
//   - sorting the EventTypes
//   - removing duplicate EventTypes
func (fb filterBuilder) AndAnyEventTypeOf(
	eventType FilterEventTypeString,
	eventTypes ...FilterEventTypeString,
) CompletedFilterItemBuilder {

	return fb.AnyEventTypeOf(eventType, eventTypes...)
}

// sanitizeEventTypes removes empty strings, sorts, and removes duplicates from event types.
func (fb filterBuilder) sanitizeEventTypes(
	eventType FilterEventTypeString,
	eventTypes ...FilterEventTypeString,
) []FilterEventTypeString {

	allEventTypes := append([]FilterEventTypeString{eventType}, eventTypes...)
	allEventTypes = slices.DeleteFunc(
		allEventTypes,
		func(e FilterEventTypeString) bool {
			return e == ""
		})
	slices.Sort(allEventTypes)
	allEventTypes = slices.Compact(allEventTypes)
	allEventTypes = slices.Clip(allEventTypes)

	return allEventTypes
}

// AnyPredicateOf adds one or multiple FilterPredicate(s) to the current FilterItem expecting ANY predicate to match.
//
// It sanitizes the input:
//   - removing empty/partial FilterPredicate(s) (key or val is "")
//   - sorting the FilterPredicate(s)
//   - removing duplicate FilterPredicate(s)
func (fb filterBuilder) AnyPredicateOf(
	predicate FilterPredicate,
	predicates ...FilterPredicate,
) FilterItemBuilderLackingEventTypes {

	fb.currentFilterItem.predicates = append(
		fb.currentFilterItem.predicates,
		fb.sanitizePredicates(predicate, predicates...)...,
	)

	return fb
}

// AndAnyPredicateOf adds one or multiple FilterPredicate(s) to the current FilterItem expecting ANY predicate to match.
//
// It sanitizes the input:
//   - removing empty/partial FilterPredicate(s) (key or val is "")
//   - sorting the FilterPredicate(s)
//   - removing duplicate FilterPredicate(s)
func (fb filterBuilder) AndAnyPredicateOf(
	predicate FilterPredicate,
	predicates ...FilterPredicate,
) CompletedFilterItemBuilder {

	return fb.AnyPredicateOf(predicate, predicates...)
}

// AllPredicatesOf adds one or multiple FilterPredicate(s) to the current FilterItem expecting ALL predicates to match.
//
// It sanitizes the input:
//   - removing empty/partial FilterPredicate(s) (key or val is "")
//   - sorting the FilterPredicate(s)
//   - removing duplicate FilterPredicate(s)
func (fb filterBuilder) AllPredicatesOf(
	predicate FilterPredicate,
	predicates ...FilterPredicate,
) FilterItemBuilderLackingEventTypes {

	fb.currentFilterItem.allPredicatesMustMatch = true

	fb.currentFilterItem.predicates = append(
		fb.currentFilterItem.predicates,
		fb.sanitizePredicates(predicate, predicates...)...,
	)

	return fb
}

// AndAllPredicatesOf adds one or multiple FilterPredicate(s) to the current FilterItem expecting ALL predicates to match.
//
// It sanitizes the input:
//   - removing empty/partial FilterPredicate(s) (key or val is "")
//   - sorting the FilterPredicate(s)
//   - removing duplicate FilterPredicate(s)
func (fb filterBuilder) AndAllPredicatesOf(
	predicate FilterPredicate,
	predicates ...FilterPredicate,
) CompletedFilterItemBuilder {

	return fb.AllPredicatesOf(predicate, predicates...)
}

// sanitizePredicates removes empty predicates, sorts by key, and removes duplicates.
func (fb filterBuilder) sanitizePredicates(
	predicate FilterPredicate,
	predicates ...FilterPredicate,
) []FilterPredicate {

	allPredicates := append([]FilterPredicate{predicate}, predicates...)
	allPredicates = slices.DeleteFunc(allPredicates, func(e FilterPredicate) bool { return len(e.key) == 0 || len(e.val) == 0 })
	slices.SortFunc(
		allPredicates,
		func(a, b FilterPredicate) int {
			if a.key > b.key {
				return 1
			}

			if a.key < b.key {
				return -1
			}

			return 0
		})

	allPredicates = slices.Compact(allPredicates)
	allPredicates = slices.Clip(allPredicates)

	return allPredicates
}

// sanitizeSequenceNumber converts negative values to 0.
func (fb filterBuilder) sanitizeSequenceNumber(sequenceNumber uint) uint {
	// uint is always >= 0, so no sanitization needed
	return sequenceNumber
}

// OccurredFrom sets the lower boundary for occurredAt (including this timestamp) for the whole Filter.
func (fb filterBuilder) OccurredFrom(occurredFrom time.Time) CompletedFilterItemBuilderWithOccurredFrom {
	fb.filter.occurredFrom = occurredFrom

	return fb
}

// OccurredUntil sets the upper boundary for occurredAt (including this timestamp) for the whole Filter.
//
// Currently, there is NO check if OccurredUntil is later than OccurredFrom!
func (fb filterBuilder) OccurredUntil(occurredUntil time.Time) CompletedFilterItemBuilderWithOccurredUntil {
	fb.filter.occurredUntil = occurredUntil

	return fb
}

// AndOccurredUntil sets the upper boundary for occurredAt (including this timestamp) for the whole Filter.
//
// Currently, there is NO check if AndOccurredUntil is later than OccurredFrom!
func (fb filterBuilder) AndOccurredUntil(occurredUntil time.Time) CompletedFilterItemBuilderWithOccurredFromToUntil {
	fb.filter.occurredUntil = occurredUntil

	return fb
}

// WithSequenceNumberHigherThan sets the sequence number boundary (exclusive) for the whole Filter.
// This makes time boundaries unavailable (mutually exclusive).
//
// It sanitizes the input:
//   - negative values are converted to 0 (sequences start at 1)
func (fb filterBuilder) WithSequenceNumberHigherThan(sequenceNumber uint) CompletedFilterItemBuilderWithSequenceNumber {
	fb.filter.sequenceNumberHigherThan = fb.sanitizeSequenceNumber(sequenceNumber)

	return fb
}

// OrMatching finalizes the current FilterItem and starts a new one.
func (fb filterBuilder) OrMatching() EmptyFilterItemBuilder {
	fb.filter.items = append(fb.filter.items, fb.currentFilterItem)
	fb.currentFilterItem = FilterItem{}

	return fb
}

// MatchingAnyEvent directly creates an empty filter.
// WARNING: This returns ALL events and should not be used in production.
func (fb filterBuilder) MatchingAnyEvent() Filter {
	return fb.filter
}

// Finalize returns the Filter once it has at least one FilterItem with at least one EventType OR one Predicate.
func (fb filterBuilder) Finalize() Filter {
	fb.filter.items = append(fb.filter.items, fb.currentFilterItem)

	return fb.filter
}

/***** Filter Reopening Interfaces *****/

// SequenceFilteringCapable represents a filter state that can accept sequence number filtering.
// This interface provides compile-time safety - you can only call WithSequenceNumberHigherThan
// on filters that are compatible (no time boundaries set).
type SequenceFilteringCapable interface {
	// WithSequenceNumberHigherThan sets the sequence number boundary (exclusive) for the reopened Filter.
	WithSequenceNumberHigherThan(sequenceNumber uint) CompletedFilterItemBuilderWithSequenceNumber
}

// SequenceFilteringIncompatible represents a filter state that cannot accept sequence number filtering.
// This interface provides compile-time safety - attempting to call WithSequenceNumberHigherThan
// will result in a compile-time error.
type SequenceFilteringIncompatible interface {
	// CannotAddSequenceFiltering documents why sequence filtering is not possible on this filter.
	CannotAddSequenceFiltering() string
}

/***** Filter Reopening Implementation *****/

// sequenceFilterBuilder implements SequenceFilteringCapable for filters that can accept sequence filtering.
type sequenceFilterBuilder struct {
	baseFilter Filter
}

// WithSequenceNumberHigherThan creates a new filter with sequence number filtering.
// It directly clones the base filter and sets the sequence number, clearing any time boundaries.
func (sfb *sequenceFilterBuilder) WithSequenceNumberHigherThan(sequenceNumber uint) CompletedFilterItemBuilderWithSequenceNumber {
	// uint is always >= 0, so no sanitization needed

	// Clone the base filter and modify the sequence number
	clonedFilter := Filter{
		items:                    sfb.baseFilter.items, // Reuse slice (immutable)
		occurredFrom:             time.Time{},          // Clear time boundaries
		occurredUntil:            time.Time{},          // Clear time boundaries
		sequenceNumberHigherThan: sequenceNumber,
	}

	// Return a completed builder that can only finalize
	return &sequenceFilterCompleted{filter: clonedFilter}
}

// sequenceFilterCompleted implements CompletedFilterItemBuilderWithSequenceNumber for the cloned filter.
type sequenceFilterCompleted struct {
	filter Filter
}

// Finalize returns the cloned filter with sequence number filtering applied.
func (sfc *sequenceFilterCompleted) Finalize() Filter {
	return sfc.filter
}

// incompatibleFilterState implements SequenceFilteringIncompatible for filters that cannot accept sequence filtering.
type incompatibleFilterState struct {
	reason string
}

// CannotAddSequenceFiltering returns the reason why sequence filtering is not possible.
func (ifs *incompatibleFilterState) CannotAddSequenceFiltering() string {
	return ifs.reason
}
