package fixtures

import (
	"errors"

	jsoniter "github.com/json-iterator/go"

	"github.com/AntonStoeckl/dynamic-streams-eventstore-go/eventstore"
	"github.com/AntonStoeckl/dynamic-streams-eventstore-go/testutil/eventstore/shared"
)

// ErrMappingToStorableEventFailedForDomainEvent is returned when domain event serialization fails.
var ErrMappingToStorableEventFailedForDomainEvent = errors.New("mapping to storable event failed for domain event")

// ErrMappingToStorableEventFailedForMetadata is returned when metadata serialization fails.
var ErrMappingToStorableEventFailedForMetadata = errors.New("mapping to storable event failed for metadata")

// StorableEventFrom converts a DomainEvent and EventMetadata to a StorableEvent.
func StorableEventFrom(event shared.DomainEvent, metadata shared.EventMetadata) (eventstore.StorableEvent, error) {
	payloadJSON, err := jsoniter.ConfigFastest.Marshal(event)
	if err != nil {
		return eventstore.StorableEvent{}, errors.Join(ErrMappingToStorableEventFailedForDomainEvent, err)
	}

	metadataJSON, err := jsoniter.ConfigFastest.Marshal(metadata)
	if err != nil {
		return eventstore.StorableEvent{}, errors.Join(ErrMappingToStorableEventFailedForMetadata, err)
	}

	storableEvent, err := eventstore.BuildStorableEvent(
		event.IsEventType(),
		event.HasOccurredAt(),
		payloadJSON,
		metadataJSON,
	)

	if err != nil {
		return eventstore.StorableEvent{}, errors.Join(ErrMappingToStorableEventFailedForDomainEvent, err)
	}

	return storableEvent, nil
}

// StorableEventWithEmptyMetadataFrom converts a DomainEvent to a StorableEvent with empty metadata.
func StorableEventWithEmptyMetadataFrom(event shared.DomainEvent) (eventstore.StorableEvent, error) {
	payloadJSON, err := jsoniter.ConfigFastest.Marshal(event)
	if err != nil {
		return eventstore.StorableEvent{}, errors.Join(ErrMappingToStorableEventFailedForDomainEvent, err)
	}

	storableEvent, err := eventstore.BuildStorableEventWithEmptyMetadata(
		event.IsEventType(),
		event.HasOccurredAt(),
		payloadJSON,
	)

	if err != nil {
		return eventstore.StorableEvent{}, errors.Join(ErrMappingToStorableEventFailedForDomainEvent, err)
	}

	return storableEvent, nil
}
