// Code generated by Fern. DO NOT EDIT.

package entities

import (
	context "context"
	v2 "github.com/anduril/lattice-sdk-go/v2"
	core "github.com/anduril/lattice-sdk-go/v2/core"
	internal "github.com/anduril/lattice-sdk-go/v2/internal"
	option "github.com/anduril/lattice-sdk-go/v2/option"
	http "net/http"
)

type Client struct {
	WithRawResponse *RawClient

	baseURL string
	caller  *internal.Caller
	header  http.Header
}

func NewClient(opts ...option.RequestOption) *Client {
	options := core.NewRequestOptions(opts...)
	return &Client{
		WithRawResponse: NewRawClient(options),
		baseURL:         options.BaseURL,
		caller: internal.NewCaller(
			&internal.CallerParams{
				Client:      options.HTTPClient,
				MaxAttempts: options.MaxAttempts,
			},
		),
		header: options.ToHeader(),
	}
}

// Publish an entity for ingest into the Entities API. Entities created with this method are "owned" by the originator: other sources,
// such as the UI, may not edit or delete these entities. The server validates entities at API call time and
// returns an error if the entity is invalid.
//
// An entity ID must be provided when calling this endpoint. If the entity referenced by the entity ID does not exist
// then it will be created. Otherwise the entity will be updated. An entity will only be updated if its
// provenance.sourceUpdateTime is greater than the provenance.sourceUpdateTime of the existing entity.
func (c *Client) PublishEntity(
	ctx context.Context,
	request *v2.Entity,
	opts ...option.RequestOption,
) (*v2.Entity, error) {
	response, err := c.WithRawResponse.PublishEntity(
		ctx,
		request,
		opts...,
	)
	if err != nil {
		return nil, err
	}
	return response.Body, nil
}

func (c *Client) GetEntity(
	ctx context.Context,
	// ID of the entity to return
	entityID string,
	opts ...option.RequestOption,
) (*v2.Entity, error) {
	response, err := c.WithRawResponse.GetEntity(
		ctx,
		entityID,
		opts...,
	)
	if err != nil {
		return nil, err
	}
	return response.Body, nil
}

// Only fields marked with overridable can be overridden. Please refer to our documentation to see the comprehensive
// list of fields that can be overridden. The entity in the request body should only have a value set on the field
// specified in the field path parameter. Field paths are rooted in the base entity object and must be represented
// using lower_snake_case. Do not include "entity" in the field path.
//
// Note that overrides are applied in an eventually consistent manner. If multiple overrides are created
// concurrently for the same field path, the last writer wins.
func (c *Client) OverrideEntity(
	ctx context.Context,
	// The unique ID of the entity to override
	entityID string,
	// fieldPath to override
	fieldPath string,
	request *v2.EntityOverride,
	opts ...option.RequestOption,
) (*v2.Entity, error) {
	response, err := c.WithRawResponse.OverrideEntity(
		ctx,
		entityID,
		fieldPath,
		request,
		opts...,
	)
	if err != nil {
		return nil, err
	}
	return response.Body, nil
}

// This operation clears the override value from the specified field path on the entity.
func (c *Client) RemoveEntityOverride(
	ctx context.Context,
	// The unique ID of the entity to undo an override from.
	entityID string,
	// The fieldPath to clear overrides from.
	fieldPath string,
	opts ...option.RequestOption,
) (*v2.Entity, error) {
	response, err := c.WithRawResponse.RemoveEntityOverride(
		ctx,
		entityID,
		fieldPath,
		opts...,
	)
	if err != nil {
		return nil, err
	}
	return response.Body, nil
}

// This is a long polling API that will first return all pre-existing data and then return all new data as
// it becomes available. If you want to start a new polling session then open a request with an empty
// 'sessionToken' in the request body. The server will return a new session token in the response.
// If you want to retrieve the next batch of results from an existing polling session then send the session
// token you received from the server in the request body. If no new data is available then the server will
// hold the connection open for up to 5 minutes. After the 5 minute timeout period, the server will close the
// connection with no results and you may resume polling with the same session token. If your session falls behind
// more than 3x the total number of entities in the environment, the server will terminate your session.
// In this case you must start a new session by sending a request with an empty session token.
func (c *Client) LongPollEntityEvents(
	ctx context.Context,
	request *v2.EntityEventRequest,
	opts ...option.RequestOption,
) (*v2.EntityEventResponse, error) {
	response, err := c.WithRawResponse.LongPollEntityEvents(
		ctx,
		request,
		opts...,
	)
	if err != nil {
		return nil, err
	}
	return response.Body, nil
}

// Establishes a persistent connection to stream entity events as they occur.
func (c *Client) StreamEntities(
	ctx context.Context,
	request *v2.EntityStreamRequest,
	opts ...option.RequestOption,
) (*core.Stream[v2.StreamEntitiesResponse], error) {
	options := core.NewRequestOptions(opts...)
	baseURL := internal.ResolveBaseURL(
		options.BaseURL,
		c.baseURL,
		"https://example.developer.anduril.com",
	)
	endpointURL := baseURL + "/api/v1/entities/stream"
	headers := internal.MergeHeaders(
		c.header.Clone(),
		options.ToHeader(),
	)
	headers.Add("Accept", "text/event-stream")
	headers.Add("Content-Type", "application/json")
	errorCodes := internal.ErrorCodes{
		400: func(apiError *core.APIError) error {
			return &v2.BadRequestError{
				APIError: apiError,
			}
		},
		401: func(apiError *core.APIError) error {
			return &v2.UnauthorizedError{
				APIError: apiError,
			}
		},
	}
	streamer := internal.NewStreamer[v2.StreamEntitiesResponse](c.caller)
	return streamer.Stream(
		ctx,
		&internal.StreamParams{
			URL:             endpointURL,
			Method:          http.MethodPost,
			Headers:         headers,
			MaxAttempts:     options.MaxAttempts,
			BodyProperties:  options.BodyProperties,
			QueryParameters: options.QueryParameters,
			Client:          options.HTTPClient,
			Prefix:          internal.DefaultSSEDataPrefix,
			Terminator:      internal.DefaultSSETerminator,
			Format:          core.StreamFormatSSE,
			Request:         request,
			ErrorDecoder:    internal.NewErrorDecoder(errorCodes),
		},
	)
}
