// Code generated by Fern. DO NOT EDIT.

package Lattice

import (
	json "encoding/json"
	fmt "fmt"
	internal "github.com/anduril/lattice-sdk-go/v2/internal"
	time "time"
)

type EntityEventRequest struct {
	// Long-poll session identifier. Leave empty to start a new polling session.
	SessionToken string `json:"sessionToken" url:"-"`
	// Maximum size of response batch. Defaults to 100. Must be between 1 and 2000 (inclusive).
	BatchSize *int `json:"batchSize,omitempty" url:"-"`
}

type EntityOverride struct {
	// The entity containing the overridden fields. The service will extract the overridable fields from
	// the object and ignore all other fields.
	Entity *Entity `json:"entity,omitempty" url:"-"`
	// Additional information about the source of the override.
	Provenance *Provenance `json:"provenance,omitempty" url:"-"`
}

type EntityStreamRequest struct {
	// at what interval to send heartbeat events, defaults to 30s.
	HeartbeatIntervalMs *int `json:"heartbeatIntervalMS,omitempty" url:"-"`
	// only stream pre-existing entities in the environment and then close the connection, defaults to false.
	PreExistingOnly *bool `json:"preExistingOnly,omitempty" url:"-"`
	// list of components to include, leave empty to include all components.
	ComponentsToInclude []string `json:"componentsToInclude,omitempty" url:"-"`
}

// Event representing some type of entity change.
type EntityEvent struct {
	EventType *EntityEventEventType `json:"eventType,omitempty" url:"eventType,omitempty"`
	Time      *time.Time            `json:"time,omitempty" url:"time,omitempty"`
	Entity    *Entity               `json:"entity,omitempty" url:"entity,omitempty"`

	extraProperties map[string]interface{}
	rawJSON         json.RawMessage
}

func (e *EntityEvent) GetEventType() *EntityEventEventType {
	if e == nil {
		return nil
	}
	return e.EventType
}

func (e *EntityEvent) GetTime() *time.Time {
	if e == nil {
		return nil
	}
	return e.Time
}

func (e *EntityEvent) GetEntity() *Entity {
	if e == nil {
		return nil
	}
	return e.Entity
}

func (e *EntityEvent) GetExtraProperties() map[string]interface{} {
	return e.extraProperties
}

func (e *EntityEvent) UnmarshalJSON(data []byte) error {
	type embed EntityEvent
	var unmarshaler = struct {
		embed
		Time *internal.DateTime `json:"time,omitempty"`
	}{
		embed: embed(*e),
	}
	if err := json.Unmarshal(data, &unmarshaler); err != nil {
		return err
	}
	*e = EntityEvent(unmarshaler.embed)
	e.Time = unmarshaler.Time.TimePtr()
	extraProperties, err := internal.ExtractExtraProperties(data, *e)
	if err != nil {
		return err
	}
	e.extraProperties = extraProperties
	e.rawJSON = json.RawMessage(data)
	return nil
}

func (e *EntityEvent) MarshalJSON() ([]byte, error) {
	type embed EntityEvent
	var marshaler = struct {
		embed
		Time *internal.DateTime `json:"time,omitempty"`
	}{
		embed: embed(*e),
		Time:  internal.NewOptionalDateTime(e.Time),
	}
	return json.Marshal(marshaler)
}

func (e *EntityEvent) String() string {
	if len(e.rawJSON) > 0 {
		if value, err := internal.StringifyJSON(e.rawJSON); err == nil {
			return value
		}
	}
	if value, err := internal.StringifyJSON(e); err == nil {
		return value
	}
	return fmt.Sprintf("%#v", e)
}

type EntityEventEventType string

const (
	EntityEventEventTypeEventTypeInvalid            EntityEventEventType = "EVENT_TYPE_INVALID"
	EntityEventEventTypeEventTypeCreated            EntityEventEventType = "EVENT_TYPE_CREATED"
	EntityEventEventTypeEventTypeUpdate             EntityEventEventType = "EVENT_TYPE_UPDATE"
	EntityEventEventTypeEventTypeDeleted            EntityEventEventType = "EVENT_TYPE_DELETED"
	EntityEventEventTypeEventTypePreexisting        EntityEventEventType = "EVENT_TYPE_PREEXISTING"
	EntityEventEventTypeEventTypePostExpiryOverride EntityEventEventType = "EVENT_TYPE_POST_EXPIRY_OVERRIDE"
)

func NewEntityEventEventTypeFromString(s string) (EntityEventEventType, error) {
	switch s {
	case "EVENT_TYPE_INVALID":
		return EntityEventEventTypeEventTypeInvalid, nil
	case "EVENT_TYPE_CREATED":
		return EntityEventEventTypeEventTypeCreated, nil
	case "EVENT_TYPE_UPDATE":
		return EntityEventEventTypeEventTypeUpdate, nil
	case "EVENT_TYPE_DELETED":
		return EntityEventEventTypeEventTypeDeleted, nil
	case "EVENT_TYPE_PREEXISTING":
		return EntityEventEventTypeEventTypePreexisting, nil
	case "EVENT_TYPE_POST_EXPIRY_OVERRIDE":
		return EntityEventEventTypeEventTypePostExpiryOverride, nil
	}
	var t EntityEventEventType
	return "", fmt.Errorf("%s is not a valid %T", s, t)
}

func (e EntityEventEventType) Ptr() *EntityEventEventType {
	return &e
}

type EntityEventResponse struct {
	// Long-poll session identifier. Use this token to resume polling on subsequent requests.
	SessionToken *string        `json:"sessionToken,omitempty" url:"sessionToken,omitempty"`
	EntityEvents []*EntityEvent `json:"entityEvents,omitempty" url:"entityEvents,omitempty"`

	extraProperties map[string]interface{}
	rawJSON         json.RawMessage
}

func (e *EntityEventResponse) GetSessionToken() *string {
	if e == nil {
		return nil
	}
	return e.SessionToken
}

func (e *EntityEventResponse) GetEntityEvents() []*EntityEvent {
	if e == nil {
		return nil
	}
	return e.EntityEvents
}

func (e *EntityEventResponse) GetExtraProperties() map[string]interface{} {
	return e.extraProperties
}

func (e *EntityEventResponse) UnmarshalJSON(data []byte) error {
	type unmarshaler EntityEventResponse
	var value unmarshaler
	if err := json.Unmarshal(data, &value); err != nil {
		return err
	}
	*e = EntityEventResponse(value)
	extraProperties, err := internal.ExtractExtraProperties(data, *e)
	if err != nil {
		return err
	}
	e.extraProperties = extraProperties
	e.rawJSON = json.RawMessage(data)
	return nil
}

func (e *EntityEventResponse) String() string {
	if len(e.rawJSON) > 0 {
		if value, err := internal.StringifyJSON(e.rawJSON); err == nil {
			return value
		}
	}
	if value, err := internal.StringifyJSON(e); err == nil {
		return value
	}
	return fmt.Sprintf("%#v", e)
}

type EntityStreamEvent struct {
	EventType *EntityEventEventType `json:"eventType,omitempty" url:"eventType,omitempty"`
	Time      *time.Time            `json:"time,omitempty" url:"time,omitempty"`
	Entity    *Entity               `json:"entity,omitempty" url:"entity,omitempty"`

	extraProperties map[string]interface{}
	rawJSON         json.RawMessage
}

func (e *EntityStreamEvent) GetEventType() *EntityEventEventType {
	if e == nil {
		return nil
	}
	return e.EventType
}

func (e *EntityStreamEvent) GetTime() *time.Time {
	if e == nil {
		return nil
	}
	return e.Time
}

func (e *EntityStreamEvent) GetEntity() *Entity {
	if e == nil {
		return nil
	}
	return e.Entity
}

func (e *EntityStreamEvent) GetExtraProperties() map[string]interface{} {
	return e.extraProperties
}

func (e *EntityStreamEvent) UnmarshalJSON(data []byte) error {
	type embed EntityStreamEvent
	var unmarshaler = struct {
		embed
		Time *internal.DateTime `json:"time,omitempty"`
	}{
		embed: embed(*e),
	}
	if err := json.Unmarshal(data, &unmarshaler); err != nil {
		return err
	}
	*e = EntityStreamEvent(unmarshaler.embed)
	e.Time = unmarshaler.Time.TimePtr()
	extraProperties, err := internal.ExtractExtraProperties(data, *e)
	if err != nil {
		return err
	}
	e.extraProperties = extraProperties
	e.rawJSON = json.RawMessage(data)
	return nil
}

func (e *EntityStreamEvent) MarshalJSON() ([]byte, error) {
	type embed EntityStreamEvent
	var marshaler = struct {
		embed
		Time *internal.DateTime `json:"time,omitempty"`
	}{
		embed: embed(*e),
		Time:  internal.NewOptionalDateTime(e.Time),
	}
	return json.Marshal(marshaler)
}

func (e *EntityStreamEvent) String() string {
	if len(e.rawJSON) > 0 {
		if value, err := internal.StringifyJSON(e.rawJSON); err == nil {
			return value
		}
	}
	if value, err := internal.StringifyJSON(e); err == nil {
		return value
	}
	return fmt.Sprintf("%#v", e)
}

type EntityStreamHeartbeat struct {
	// timestamp of the heartbeat
	Timestamp *time.Time `json:"timestamp,omitempty" url:"timestamp,omitempty"`

	extraProperties map[string]interface{}
	rawJSON         json.RawMessage
}

func (e *EntityStreamHeartbeat) GetTimestamp() *time.Time {
	if e == nil {
		return nil
	}
	return e.Timestamp
}

func (e *EntityStreamHeartbeat) GetExtraProperties() map[string]interface{} {
	return e.extraProperties
}

func (e *EntityStreamHeartbeat) UnmarshalJSON(data []byte) error {
	type embed EntityStreamHeartbeat
	var unmarshaler = struct {
		embed
		Timestamp *internal.DateTime `json:"timestamp,omitempty"`
	}{
		embed: embed(*e),
	}
	if err := json.Unmarshal(data, &unmarshaler); err != nil {
		return err
	}
	*e = EntityStreamHeartbeat(unmarshaler.embed)
	e.Timestamp = unmarshaler.Timestamp.TimePtr()
	extraProperties, err := internal.ExtractExtraProperties(data, *e)
	if err != nil {
		return err
	}
	e.extraProperties = extraProperties
	e.rawJSON = json.RawMessage(data)
	return nil
}

func (e *EntityStreamHeartbeat) MarshalJSON() ([]byte, error) {
	type embed EntityStreamHeartbeat
	var marshaler = struct {
		embed
		Timestamp *internal.DateTime `json:"timestamp,omitempty"`
	}{
		embed:     embed(*e),
		Timestamp: internal.NewOptionalDateTime(e.Timestamp),
	}
	return json.Marshal(marshaler)
}

func (e *EntityStreamHeartbeat) String() string {
	if len(e.rawJSON) > 0 {
		if value, err := internal.StringifyJSON(e.rawJSON); err == nil {
			return value
		}
	}
	if value, err := internal.StringifyJSON(e); err == nil {
		return value
	}
	return fmt.Sprintf("%#v", e)
}

type HeartbeatObject struct {
	// timestamp of the heartbeat
	Timestamp *time.Time `json:"timestamp,omitempty" url:"timestamp,omitempty"`

	extraProperties map[string]interface{}
	rawJSON         json.RawMessage
}

func (h *HeartbeatObject) GetTimestamp() *time.Time {
	if h == nil {
		return nil
	}
	return h.Timestamp
}

func (h *HeartbeatObject) GetExtraProperties() map[string]interface{} {
	return h.extraProperties
}

func (h *HeartbeatObject) UnmarshalJSON(data []byte) error {
	type embed HeartbeatObject
	var unmarshaler = struct {
		embed
		Timestamp *internal.DateTime `json:"timestamp,omitempty"`
	}{
		embed: embed(*h),
	}
	if err := json.Unmarshal(data, &unmarshaler); err != nil {
		return err
	}
	*h = HeartbeatObject(unmarshaler.embed)
	h.Timestamp = unmarshaler.Timestamp.TimePtr()
	extraProperties, err := internal.ExtractExtraProperties(data, *h)
	if err != nil {
		return err
	}
	h.extraProperties = extraProperties
	h.rawJSON = json.RawMessage(data)
	return nil
}

func (h *HeartbeatObject) MarshalJSON() ([]byte, error) {
	type embed HeartbeatObject
	var marshaler = struct {
		embed
		Timestamp *internal.DateTime `json:"timestamp,omitempty"`
	}{
		embed:     embed(*h),
		Timestamp: internal.NewOptionalDateTime(h.Timestamp),
	}
	return json.Marshal(marshaler)
}

func (h *HeartbeatObject) String() string {
	if len(h.rawJSON) > 0 {
		if value, err := internal.StringifyJSON(h.rawJSON); err == nil {
			return value
		}
	}
	if value, err := internal.StringifyJSON(h); err == nil {
		return value
	}
	return fmt.Sprintf("%#v", h)
}

// The stream event response.
type StreamEntitiesResponse struct {
	Event     string
	Heartbeat *EntityStreamHeartbeat
	Entity    *EntityStreamEvent
}

func (s *StreamEntitiesResponse) GetEvent() string {
	if s == nil {
		return ""
	}
	return s.Event
}

func (s *StreamEntitiesResponse) GetHeartbeat() *EntityStreamHeartbeat {
	if s == nil {
		return nil
	}
	return s.Heartbeat
}

func (s *StreamEntitiesResponse) GetEntity() *EntityStreamEvent {
	if s == nil {
		return nil
	}
	return s.Entity
}

func (s *StreamEntitiesResponse) UnmarshalJSON(data []byte) error {
	var unmarshaler struct {
		Event string `json:"event"`
	}
	if err := json.Unmarshal(data, &unmarshaler); err != nil {
		return err
	}
	s.Event = unmarshaler.Event
	if unmarshaler.Event == "" {
		return fmt.Errorf("%T did not include discriminant event", s)
	}
	switch unmarshaler.Event {
	case "heartbeat":
		value := new(EntityStreamHeartbeat)
		if err := json.Unmarshal(data, &value); err != nil {
			return err
		}
		s.Heartbeat = value
	case "entity":
		value := new(EntityStreamEvent)
		if err := json.Unmarshal(data, &value); err != nil {
			return err
		}
		s.Entity = value
	}
	return nil
}

func (s StreamEntitiesResponse) MarshalJSON() ([]byte, error) {
	if err := s.validate(); err != nil {
		return nil, err
	}
	if s.Heartbeat != nil {
		return internal.MarshalJSONWithExtraProperty(s.Heartbeat, "event", "heartbeat")
	}
	if s.Entity != nil {
		return internal.MarshalJSONWithExtraProperty(s.Entity, "event", "entity")
	}
	return nil, fmt.Errorf("type %T does not define a non-empty union type", s)
}

type StreamEntitiesResponseVisitor interface {
	VisitHeartbeat(*EntityStreamHeartbeat) error
	VisitEntity(*EntityStreamEvent) error
}

func (s *StreamEntitiesResponse) Accept(visitor StreamEntitiesResponseVisitor) error {
	if s.Heartbeat != nil {
		return visitor.VisitHeartbeat(s.Heartbeat)
	}
	if s.Entity != nil {
		return visitor.VisitEntity(s.Entity)
	}
	return fmt.Errorf("type %T does not define a non-empty union type", s)
}

func (s *StreamEntitiesResponse) validate() error {
	if s == nil {
		return fmt.Errorf("type %T is nil", s)
	}
	var fields []string
	if s.Heartbeat != nil {
		fields = append(fields, "heartbeat")
	}
	if s.Entity != nil {
		fields = append(fields, "entity")
	}
	if len(fields) == 0 {
		if s.Event != "" {
			return fmt.Errorf("type %T defines a discriminant set to %q but the field is not set", s, s.Event)
		}
		return fmt.Errorf("type %T is empty", s)
	}
	if len(fields) > 1 {
		return fmt.Errorf("type %T defines values for %s, but only one value is allowed", s, fields)
	}
	if s.Event != "" {
		field := fields[0]
		if s.Event != field {
			return fmt.Errorf(
				"type %T defines a discriminant set to %q, but it does not match the %T field; either remove or update the discriminant to match",
				s,
				s.Event,
				s,
			)
		}
	}
	return nil
}
