package meilisearch

import (
	"time"

	"github.com/golang-jwt/jwt/v4"
)

type (
	ContentEncoding          string
	EncodingCompressionLevel int
)

const (
	DefaultLimit int64 = 20

	contentTypeJSON   string = "application/json"
	contentTypeNDJSON string = "application/x-ndjson"
	contentTypeCSV    string = "text/csv"

	GzipEncoding    ContentEncoding = "gzip"
	DeflateEncoding ContentEncoding = "deflate"
	BrotliEncoding  ContentEncoding = "br"

	NoCompression          EncodingCompressionLevel = 0
	BestSpeed              EncodingCompressionLevel = 1
	BestCompression        EncodingCompressionLevel = 9
	DefaultCompression     EncodingCompressionLevel = -1
	HuffmanOnlyCompression EncodingCompressionLevel = -2
	ConstantCompression    EncodingCompressionLevel = -2
	StatelessCompression   EncodingCompressionLevel = -3

	nullBody = "null"
)

func (c ContentEncoding) String() string { return string(c) }

func (c ContentEncoding) IsZero() bool { return c == "" }

func (c EncodingCompressionLevel) Int() int { return int(c) }

type IndexConfig struct {
	// Uid is the unique identifier of a given index.
	Uid string
	// PrimaryKey is optional
	PrimaryKey string
}

type IndexResult struct {
	UID        string    `json:"uid"`
	CreatedAt  time.Time `json:"createdAt"`
	UpdatedAt  time.Time `json:"updatedAt"`
	PrimaryKey string    `json:"primaryKey,omitempty"`
	IndexManager
}

// IndexesResults return of multiple indexes is wrap in a IndexesResults
type IndexesResults struct {
	Results []*IndexResult `json:"results"`
	Offset  int64          `json:"offset"`
	Limit   int64          `json:"limit"`
	Total   int64          `json:"total"`
}

type IndexesQuery struct {
	Limit  int64
	Offset int64
}

// Settings is the type that represents the settings in meilisearch
type Settings struct {
	RankingRules         []string               `json:"rankingRules,omitempty"`
	DistinctAttribute    *string                `json:"distinctAttribute,omitempty"`
	SearchableAttributes []string               `json:"searchableAttributes,omitempty"`
	Dictionary           []string               `json:"dictionary,omitempty"`
	SearchCutoffMs       int64                  `json:"searchCutoffMs,omitempty"`
	ProximityPrecision   ProximityPrecisionType `json:"proximityPrecision,omitempty"`
	SeparatorTokens      []string               `json:"separatorTokens,omitempty"`
	NonSeparatorTokens   []string               `json:"nonSeparatorTokens,omitempty"`
	DisplayedAttributes  []string               `json:"displayedAttributes,omitempty"`
	StopWords            []string               `json:"stopWords,omitempty"`
	Synonyms             map[string][]string    `json:"synonyms,omitempty"`
	FilterableAttributes []string               `json:"filterableAttributes,omitempty"`
	SortableAttributes   []string               `json:"sortableAttributes,omitempty"`
	LocalizedAttributes  []*LocalizedAttributes `json:"localizedAttributes,omitempty"`
	TypoTolerance        *TypoTolerance         `json:"typoTolerance,omitempty"`
	Pagination           *Pagination            `json:"pagination,omitempty"`
	Faceting             *Faceting              `json:"faceting,omitempty"`
	Embedders            map[string]Embedder    `json:"embedders,omitempty"`
	PrefixSearch         *string                `json:"prefixSearch,omitempty"`
	FacetSearch          bool                   `json:"facetSearch,omitempty"`
}

type LocalizedAttributes struct {
	Locales           []string `json:"locales,omitempty"`
	AttributePatterns []string `json:"attributePatterns,omitempty"`
}

// TypoTolerance is the type that represents the typo tolerance setting in meilisearch
type TypoTolerance struct {
	Enabled             bool                `json:"enabled"`
	MinWordSizeForTypos MinWordSizeForTypos `json:"minWordSizeForTypos,omitempty"`
	DisableOnWords      []string            `json:"disableOnWords,omitempty"`
	DisableOnAttributes []string            `json:"disableOnAttributes,omitempty"`
}

// MinWordSizeForTypos is the type that represents the minWordSizeForTypos setting in the typo tolerance setting in meilisearch
type MinWordSizeForTypos struct {
	OneTypo  int64 `json:"oneTypo,omitempty"`
	TwoTypos int64 `json:"twoTypos,omitempty"`
}

// Pagination is the type that represents the pagination setting in meilisearch
type Pagination struct {
	MaxTotalHits int64 `json:"maxTotalHits"`
}

// Faceting is the type that represents the faceting setting in meilisearch
type Faceting struct {
	MaxValuesPerFacet int64 `json:"maxValuesPerFacet"`
	// SortFacetValuesBy index_name: alpha|count
	SortFacetValuesBy map[string]SortFacetType `json:"sortFacetValuesBy"`
}

// Embedder represents a unified configuration for various embedder types.
type Embedder struct {
	Source           string                 `json:"source"`                     // The type of embedder: "openAi", "huggingFace", "userProvided", "rest", "ollama"
	Model            string                 `json:"model,omitempty"`            // Optional for "openAi", "huggingFace", "ollama"
	APIKey           string                 `json:"apiKey,omitempty"`           // Optional for "openAi", "rest", "ollama"
	DocumentTemplate string                 `json:"documentTemplate,omitempty"` // Optional for most embedders
	Dimensions       int                    `json:"dimensions,omitempty"`       // Optional for "openAi", "rest", "userProvided", "ollama"
	Distribution     *Distribution          `json:"distribution,omitempty"`     // Optional for all embedders
	URL              string                 `json:"url,omitempty"`              // Optional for "openAi", "rest", "ollama"
	Revision         string                 `json:"revision,omitempty"`         // Optional for "huggingFace"
	Request          map[string]interface{} `json:"request,omitempty"`          // Optional for "rest"
	Response         map[string]interface{} `json:"response,omitempty"`         // Optional for "rest"
	Headers          map[string]string      `json:"headers,omitempty"`          // Optional for "rest"
}

// Distribution represents a statistical distribution with mean and standard deviation (sigma).
type Distribution struct {
	Mean  float64 `json:"mean"`  // Mean of the distribution
	Sigma float64 `json:"sigma"` // Sigma (standard deviation) of the distribution
}

// Version is the type that represents the versions in meilisearch
type Version struct {
	CommitSha  string `json:"commitSha"`
	CommitDate string `json:"commitDate"`
	PkgVersion string `json:"pkgVersion"`
}

// StatsIndex is the type that represent the stats of an index in meilisearch
type StatsIndex struct {
	NumberOfDocuments         int64            `json:"numberOfDocuments"`
	IsIndexing                bool             `json:"isIndexing"`
	FieldDistribution         map[string]int64 `json:"fieldDistribution"`
	RawDocumentDbSize         int64            `json:"rawDocumentDbSize"`
	AvgDocumentSize           int64            `json:"avgDocumentSize"`
	NumberOfEmbeddedDocuments int64            `json:"numberOfEmbeddedDocuments"`
	NumberOfEmbeddings        int64            `json:"numberOfEmbeddings"`
}

// Stats is the type that represent all stats
type Stats struct {
	DatabaseSize     int64                 `json:"databaseSize"`
	UsedDatabaseSize int64                 `json:"usedDatabaseSize"`
	LastUpdate       time.Time             `json:"lastUpdate"`
	Indexes          map[string]StatsIndex `json:"indexes"`
}

type (
	TaskType               string // TaskType is the type of a task
	SortFacetType          string // SortFacetType is type of facet sorting, alpha or count
	TaskStatus             string // TaskStatus is the status of a task.
	ProximityPrecisionType string // ProximityPrecisionType accepts one of the ByWord or ByAttribute
	MatchingStrategy       string // MatchingStrategy one of the Last, All, Frequency
)

const (
	// Last returns documents containing all the query terms first. If there are not enough results containing all
	// query terms to meet the requested limit, Meilisearch will remove one query term at a time,
	// starting from the end of the query.
	Last MatchingStrategy = "last"
	// All only returns documents that contain all query terms. Meilisearch will not match any more documents even
	// if there aren't enough to meet the requested limit.
	All MatchingStrategy = "all"
	// Frequency returns documents containing all the query terms first. If there are not enough results containing
	//all query terms to meet the requested limit, Meilisearch will remove one query term at a time, starting
	//with the word that is the most frequent in the dataset. frequency effectively gives more weight to terms
	//that appear less frequently in a set of results.
	Frequency MatchingStrategy = "frequency"
)

const (
	// ByWord calculate the precise distance between query terms. Higher precision, but may lead to longer
	// indexing time. This is the default setting
	ByWord ProximityPrecisionType = "byWord"
	// ByAttribute determine if multiple query terms are present in the same attribute.
	// Lower precision, but shorter indexing time
	ByAttribute ProximityPrecisionType = "byAttribute"
)

const (
	// TaskStatusUnknown is the default TaskStatus, should not exist
	TaskStatusUnknown TaskStatus = "unknown"
	// TaskStatusEnqueued the task request has been received and will be processed soon
	TaskStatusEnqueued TaskStatus = "enqueued"
	// TaskStatusProcessing the task is being processed
	TaskStatusProcessing TaskStatus = "processing"
	// TaskStatusSucceeded the task has been successfully processed
	TaskStatusSucceeded TaskStatus = "succeeded"
	// TaskStatusFailed a failure occurred when processing the task, no changes were made to the database
	TaskStatusFailed TaskStatus = "failed"
	// TaskStatusCanceled the task was canceled
	TaskStatusCanceled TaskStatus = "canceled"
)

const (
	SortFacetTypeAlpha SortFacetType = "alpha"
	SortFacetTypeCount SortFacetType = "count"
)

const (
	// TaskTypeIndexCreation represents an index creation
	TaskTypeIndexCreation TaskType = "indexCreation"
	// TaskTypeIndexUpdate represents an index update
	TaskTypeIndexUpdate TaskType = "indexUpdate"
	// TaskTypeIndexDeletion represents an index deletion
	TaskTypeIndexDeletion TaskType = "indexDeletion"
	// TaskTypeIndexSwap represents an index swap
	TaskTypeIndexSwap TaskType = "indexSwap"
	// TaskTypeDocumentAdditionOrUpdate represents a document addition or update in an index
	TaskTypeDocumentAdditionOrUpdate TaskType = "documentAdditionOrUpdate"
	// TaskTypeDocumentDeletion represents a document deletion from an index
	TaskTypeDocumentDeletion TaskType = "documentDeletion"
	// TaskTypeSettingsUpdate represents a settings update
	TaskTypeSettingsUpdate TaskType = "settingsUpdate"
	// TaskTypeDumpCreation represents a dump creation
	TaskTypeDumpCreation TaskType = "dumpCreation"
	// TaskTypeTaskCancelation represents a task cancelation
	TaskTypeTaskCancelation TaskType = "taskCancelation"
	// TaskTypeTaskDeletion represents a task deletion
	TaskTypeTaskDeletion TaskType = "taskDeletion"
	// TaskTypeSnapshotCreation represents a snapshot creation
	TaskTypeSnapshotCreation TaskType = "snapshotCreation"
)

// Task indicates information about a task resource
//
// Documentation: https://www.meilisearch.com/docs/learn/advanced/asynchronous_operations
type Task struct {
	Status     TaskStatus          `json:"status"`
	UID        int64               `json:"uid,omitempty"`
	TaskUID    int64               `json:"taskUid,omitempty"`
	IndexUID   string              `json:"indexUid"`
	Type       TaskType            `json:"type"`
	Error      meilisearchApiError `json:"error,omitempty"`
	Duration   string              `json:"duration,omitempty"`
	EnqueuedAt time.Time           `json:"enqueuedAt"`
	StartedAt  time.Time           `json:"startedAt,omitempty"`
	FinishedAt time.Time           `json:"finishedAt,omitempty"`
	Details    Details             `json:"details,omitempty"`
	CanceledBy int64               `json:"canceledBy,omitempty"`
}

// TaskInfo indicates information regarding a task returned by an asynchronous method
//
// Documentation: https://www.meilisearch.com/docs/reference/api/tasks#tasks
type TaskInfo struct {
	Status     TaskStatus `json:"status"`
	TaskUID    int64      `json:"taskUid"`
	IndexUID   string     `json:"indexUid"`
	Type       TaskType   `json:"type"`
	EnqueuedAt time.Time  `json:"enqueuedAt"`
}

// TasksQuery is a list of filter available to send as query parameters
type TasksQuery struct {
	UIDS             []int64
	Limit            int64
	From             int64
	IndexUIDS        []string
	Statuses         []TaskStatus
	Types            []TaskType
	CanceledBy       []int64
	BeforeEnqueuedAt time.Time
	AfterEnqueuedAt  time.Time
	BeforeStartedAt  time.Time
	AfterStartedAt   time.Time
	BeforeFinishedAt time.Time
	AfterFinishedAt  time.Time
	Reverse          bool
}

// CancelTasksQuery is a list of filter available to send as query parameters
type CancelTasksQuery struct {
	UIDS             []int64
	IndexUIDS        []string
	Statuses         []TaskStatus
	Types            []TaskType
	BeforeEnqueuedAt time.Time
	AfterEnqueuedAt  time.Time
	BeforeStartedAt  time.Time
	AfterStartedAt   time.Time
}

// DeleteTasksQuery is a list of filter available to send as query parameters
type DeleteTasksQuery struct {
	UIDS             []int64
	IndexUIDS        []string
	Statuses         []TaskStatus
	Types            []TaskType
	CanceledBy       []int64
	BeforeEnqueuedAt time.Time
	AfterEnqueuedAt  time.Time
	BeforeStartedAt  time.Time
	AfterStartedAt   time.Time
	BeforeFinishedAt time.Time
	AfterFinishedAt  time.Time
}

type Details struct {
	ReceivedDocuments    int64               `json:"receivedDocuments,omitempty"`
	IndexedDocuments     int64               `json:"indexedDocuments,omitempty"`
	DeletedDocuments     int64               `json:"deletedDocuments,omitempty"`
	PrimaryKey           string              `json:"primaryKey,omitempty"`
	ProvidedIds          int64               `json:"providedIds,omitempty"`
	RankingRules         []string            `json:"rankingRules,omitempty"`
	DistinctAttribute    *string             `json:"distinctAttribute,omitempty"`
	SearchableAttributes []string            `json:"searchableAttributes,omitempty"`
	DisplayedAttributes  []string            `json:"displayedAttributes,omitempty"`
	StopWords            []string            `json:"stopWords,omitempty"`
	Synonyms             map[string][]string `json:"synonyms,omitempty"`
	FilterableAttributes []string            `json:"filterableAttributes,omitempty"`
	SortableAttributes   []string            `json:"sortableAttributes,omitempty"`
	TypoTolerance        *TypoTolerance      `json:"typoTolerance,omitempty"`
	Pagination           *Pagination         `json:"pagination,omitempty"`
	Faceting             *Faceting           `json:"faceting,omitempty"`
	MatchedTasks         int64               `json:"matchedTasks,omitempty"`
	CanceledTasks        int64               `json:"canceledTasks,omitempty"`
	DeletedTasks         int64               `json:"deletedTasks,omitempty"`
	OriginalFilter       string              `json:"originalFilter,omitempty"`
	Swaps                []SwapIndexesParams `json:"swaps,omitempty"`
	DumpUid              string              `json:"dumpUid,omitempty"`
}

// TaskResult return of multiple tasks is wrap in a TaskResult
type TaskResult struct {
	Results []Task `json:"results"`
	Limit   int64  `json:"limit"`
	From    int64  `json:"from"`
	Next    int64  `json:"next"`
	Total   int64  `json:"total"`
}

// Key allow the user to connect to the meilisearch instance
//
// Documentation: https://www.meilisearch.com/docs/learn/security/master_api_keys#protecting-a-meilisearch-instance
type Key struct {
	Name        string    `json:"name"`
	Description string    `json:"description"`
	Key         string    `json:"key,omitempty"`
	UID         string    `json:"uid,omitempty"`
	Actions     []string  `json:"actions,omitempty"`
	Indexes     []string  `json:"indexes,omitempty"`
	CreatedAt   time.Time `json:"createdAt,omitempty"`
	UpdatedAt   time.Time `json:"updatedAt,omitempty"`
	ExpiresAt   time.Time `json:"expiresAt"`
}

// KeyParsed this structure is used to send the exact ISO-8601 time format managed by meilisearch
type KeyParsed struct {
	Name        string   `json:"name"`
	Description string   `json:"description"`
	UID         string   `json:"uid,omitempty"`
	Actions     []string `json:"actions,omitempty"`
	Indexes     []string `json:"indexes,omitempty"`
	ExpiresAt   *string  `json:"expiresAt"`
}

// KeyUpdate this structure is used to update a Key
type KeyUpdate struct {
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
}

// KeysResults return of multiple keys is wrap in a KeysResults
type KeysResults struct {
	Results []Key `json:"results"`
	Offset  int64 `json:"offset"`
	Limit   int64 `json:"limit"`
	Total   int64 `json:"total"`
}

type KeysQuery struct {
	Limit  int64
	Offset int64
}

// TenantTokenOptions information to create a tenant token
//
// ExpiresAt is a time.Time when the key will expire.
// Note that if an ExpiresAt value is included it should be in UTC time.
// ApiKey is the API key parent of the token.
type TenantTokenOptions struct {
	APIKey    string
	ExpiresAt time.Time
}

// TenantTokenClaims custom Claims structure to create a Tenant Token
type TenantTokenClaims struct {
	APIKeyUID   string      `json:"apiKeyUid"`
	SearchRules interface{} `json:"searchRules"`
	jwt.RegisteredClaims
}

//
// Request/Response
//

// CreateIndexRequest is the request body for create index method
type CreateIndexRequest struct {
	UID        string `json:"uid,omitempty"`
	PrimaryKey string `json:"primaryKey,omitempty"`
}

// SearchRequest is the request url param needed for a search query.
// This struct will be converted to url param before sent.
//
// Documentation: https://www.meilisearch.com/docs/reference/api/search#search-parameters
type SearchRequest struct {
	Offset                  int64                    `json:"offset,omitempty"`
	Limit                   int64                    `json:"limit,omitempty"`
	AttributesToRetrieve    []string                 `json:"attributesToRetrieve,omitempty"`
	AttributesToSearchOn    []string                 `json:"attributesToSearchOn,omitempty"`
	AttributesToCrop        []string                 `json:"attributesToCrop,omitempty"`
	CropLength              int64                    `json:"cropLength,omitempty"`
	CropMarker              string                   `json:"cropMarker,omitempty"`
	AttributesToHighlight   []string                 `json:"attributesToHighlight,omitempty"`
	HighlightPreTag         string                   `json:"highlightPreTag,omitempty"`
	HighlightPostTag        string                   `json:"highlightPostTag,omitempty"`
	MatchingStrategy        MatchingStrategy         `json:"matchingStrategy,omitempty"`
	Filter                  interface{}              `json:"filter,omitempty"`
	ShowMatchesPosition     bool                     `json:"showMatchesPosition,omitempty"`
	ShowRankingScore        bool                     `json:"showRankingScore,omitempty"`
	ShowRankingScoreDetails bool                     `json:"showRankingScoreDetails,omitempty"`
	Facets                  []string                 `json:"facets,omitempty"`
	Sort                    []string                 `json:"sort,omitempty"`
	Vector                  []float32                `json:"vector,omitempty"`
	HitsPerPage             int64                    `json:"hitsPerPage,omitempty"`
	Page                    int64                    `json:"page,omitempty"`
	IndexUID                string                   `json:"indexUid,omitempty"`
	Query                   string                   `json:"q"`
	Distinct                string                   `json:"distinct,omitempty"`
	Hybrid                  *SearchRequestHybrid     `json:"hybrid"`
	RetrieveVectors         bool                     `json:"retrieveVectors,omitempty"`
	RankingScoreThreshold   float64                  `json:"rankingScoreThreshold,omitempty"`
	FederationOptions       *SearchFederationOptions `json:"federationOptions,omitempty"`
	Locates                 []string                 `json:"locales,omitempty"`
}

type SearchFederationOptions struct {
	Weight float64 `json:"weight"`
}

type SearchRequestHybrid struct {
	SemanticRatio float64 `json:"semanticRatio,omitempty"`
	Embedder      string  `json:"embedder"`
}

type MultiSearchRequest struct {
	Federation *MultiSearchFederation `json:"federation,omitempty"`
	Queries    []*SearchRequest       `json:"queries"`
}

type MultiSearchFederation struct {
	Offset int64 `json:"offset,omitempty"`
	Limit  int64 `json:"limit,omitempty"`
}

// SearchResponse is the response body for search method
type SearchResponse struct {
	Hits               []interface{} `json:"hits"`
	EstimatedTotalHits int64         `json:"estimatedTotalHits,omitempty"`
	Offset             int64         `json:"offset,omitempty"`
	Limit              int64         `json:"limit,omitempty"`
	ProcessingTimeMs   int64         `json:"processingTimeMs"`
	Query              string        `json:"query"`
	FacetDistribution  interface{}   `json:"facetDistribution,omitempty"`
	TotalHits          int64         `json:"totalHits,omitempty"`
	HitsPerPage        int64         `json:"hitsPerPage,omitempty"`
	Page               int64         `json:"page,omitempty"`
	TotalPages         int64         `json:"totalPages,omitempty"`
	FacetStats         interface{}   `json:"facetStats,omitempty"`
	IndexUID           string        `json:"indexUid,omitempty"`
}

type MultiSearchResponse struct {
	Results            []SearchResponse `json:"results,omitempty"`
	Hits               []interface{}    `json:"hits,omitempty"`
	ProcessingTimeMs   int64            `json:"processingTimeMs,omitempty"`
	Offset             int64            `json:"offset,omitempty"`
	Limit              int64            `json:"limit,omitempty"`
	EstimatedTotalHits int64            `json:"estimatedTotalHits,omitempty"`
	SemanticHitCount   int64            `json:"semanticHitCount,omitempty"`
}

type FacetSearchRequest struct {
	FacetName            string   `json:"facetName,omitempty"`
	FacetQuery           string   `json:"facetQuery,omitempty"`
	Q                    string   `json:"q,omitempty"`
	Filter               string   `json:"filter,omitempty"`
	MatchingStrategy     string   `json:"matchingStrategy,omitempty"`
	AttributesToSearchOn []string `json:"attributesToSearchOn,omitempty"`
}

type FacetSearchResponse struct {
	FacetHits        []interface{} `json:"facetHits"`
	FacetQuery       string        `json:"facetQuery"`
	ProcessingTimeMs int64         `json:"processingTimeMs"`
}

// DocumentQuery is the request body get one documents method
type DocumentQuery struct {
	Fields []string `json:"fields,omitempty"`
}

// DocumentsQuery is the request body for list documents method
type DocumentsQuery struct {
	Offset int64       `json:"offset,omitempty"`
	Limit  int64       `json:"limit,omitempty"`
	Fields []string    `json:"fields,omitempty"`
	Filter interface{} `json:"filter,omitempty"`
}

// SimilarDocumentQuery is query parameters of similar documents
type SimilarDocumentQuery struct {
	Id                      interface{} `json:"id,omitempty"`
	Embedder                string      `json:"embedder"`
	AttributesToRetrieve    []string    `json:"attributesToRetrieve,omitempty"`
	Offset                  int64       `json:"offset,omitempty"`
	Limit                   int64       `json:"limit,omitempty"`
	Filter                  string      `json:"filter,omitempty"`
	ShowRankingScore        bool        `json:"showRankingScore,omitempty"`
	ShowRankingScoreDetails bool        `json:"showRankingScoreDetails,omitempty"`
	RankingScoreThreshold   float64     `json:"rankingScoreThreshold,omitempty"`
	RetrieveVectors         bool        `json:"retrieveVectors,omitempty"`
}

type SimilarDocumentResult struct {
	Hits               []interface{} `json:"hits,omitempty"`
	ID                 string        `json:"id,omitempty"`
	ProcessingTimeMS   int64         `json:"processingTimeMs,omitempty"`
	Limit              int64         `json:"limit,omitempty"`
	Offset             int64         `json:"offset,omitempty"`
	EstimatedTotalHits int64         `json:"estimatedTotalHits,omitempty"`
}

type CsvDocumentsQuery struct {
	PrimaryKey   string `json:"primaryKey,omitempty"`
	CsvDelimiter string `json:"csvDelimiter,omitempty"`
}

type DocumentsResult struct {
	Results []map[string]interface{} `json:"results"`
	Limit   int64                    `json:"limit"`
	Offset  int64                    `json:"offset"`
	Total   int64                    `json:"total"`
}

type UpdateDocumentByFunctionRequest struct {
	Filter   string                 `json:"filter,omitempty"`
	Function string                 `json:"function"`
	Context  map[string]interface{} `json:"context,omitempty"`
}

// ExperimentalFeaturesResult represents the experimental features result from the API.
type ExperimentalFeaturesBase struct {
	LogsRoute               *bool `json:"logsRoute,omitempty"`
	Metrics                 *bool `json:"metrics,omitempty"`
	EditDocumentsByFunction *bool `json:"editDocumentsByFunction,omitempty"`
	ContainsFilter          *bool `json:"containsFilter,omitempty"`
}

type ExperimentalFeaturesResult struct {
	LogsRoute               bool `json:"logsRoute"`
	Metrics                 bool `json:"metrics"`
	EditDocumentsByFunction bool `json:"editDocumentsByFunction"`
	ContainsFilter          bool `json:"containsFilter"`
}

type SwapIndexesParams struct {
	Indexes []string `json:"indexes"`
}

// RawType is an alias for raw byte[]
type RawType []byte

// Health is the request body for set meilisearch health
type Health struct {
	Status string `json:"status"`
}

// UpdateIndexRequest is the request body for update Index primary key
type UpdateIndexRequest struct {
	PrimaryKey string `json:"primaryKey"`
}

// Unknown is unknown json type
type Unknown map[string]interface{}

// UnmarshalJSON supports json.Unmarshaler interface
func (b *RawType) UnmarshalJSON(data []byte) error {
	*b = data
	return nil
}

// MarshalJSON supports json.Marshaler interface
func (b RawType) MarshalJSON() ([]byte, error) {
	return b, nil
}

func (s *SearchRequest) validate() {
	if s.Hybrid != nil && s.Hybrid.Embedder == "" {
		s.Hybrid.Embedder = "default"
	}
}
