import { IQueryFunction } from './QueryFunction';
import { IRankingFunction } from './RankingFunction';
import { IGroupByRequest } from './GroupByRequest';
import { Context } from '../ui/PipelineContext/PipelineGlobalExports';
import { ICategoryFacetRequest } from './CategoryFacetRequest';
import { IFacetRequest } from './Facet/FacetRequest';

/**
 * The format of a successful response.
 */
export type ResponseFormat = 'json' | 'opensearch-atom' | 'opensearch-rss' | 'xlsx';

/**
 * The available global configuration options when requesting facets through the [facets]{IQuery.facets} array.
 */
export interface IFacetOptions {
  /**
   * Whether the facet values should be returned in their current order.
   */
  freezeFacetOrder?: Boolean;
}

/**
 * The information about the user we'd like to check and its actions.
 */
export interface IUserActionsRequest {
  /**
   * The id of the user for which we should check the document views.
   */
  tagViewsOfUser: string;
}

/**
 * A Search API commerce request.
 */
export interface ICommerceRequest {
  /**
   * The unique identifier of the catalog to query.
   *
   * **Example:** `46bc4275-e613-4dd5-b1ea-3e5aca1bcd9d`
   */
  catalogId?: string;
  /**
   * A mandatory query expression to apply if the commerce request affects the query.
   * **Example:** `@storeid==1001`
   */
  filter?: string;
  /**
   * The way the commerce request should affect query results.
   * **Example:** `selectCatalogObjects`
   */
  operation?: 'selectCatalogObjects' | 'excludeCatalogObjects';
}

/**
 * The IQuery interface describes a query that can be performed on the Coveo REST Search API.
 *
 * For basic usage, see the {@link IQuery.q} and {@link IQuery.aq} properties.
 *
 * In a normal scenario, a query is built by the {@link QueryBuilder} class.
 */
export interface IQuery {
  /**
   * The basic query expression. <br/>
   * This is typically the query expression entered by the user in a query box.<br/>
   * Since this part of the query is expected to come from user input, it is processed by the Did You Mean feature.
   */
  q: string;
  /**
   * The advanced query expression.<br/>
   * This is the part of the query expression generated by code based on various rules.<br/>
   * eg: Selecting a facet value will cause an expression to be added to the advanced query expression.
   */
  aq?: string;
  /**
   * The constant query expression.<br/>
   * This part of the expression is much alike the advanced query expression, but it is meant to hold expressions that are constant for all users of a search interface/widget.<br/>
   * The results of evaluating those expressions are kept in a special index cache, to avoid re-evaluating them on each query.<br/>
   * You must be careful to not include dynamic parts in this expression, otherwise you risk filling up the cache with useless data and this might have a negative impact on performance.<br/>
   * Expressions other than cq also benefit from caching in the index, but using cq allows to explicitly require that a part of the query be included in the cache.
   */
  cq?: string;
  /**
   * The contextual text.<br/>
   * This is the contextual text part of the query. It uses the Coveo Machine Learning service to pick key keywords from
   * the text and add them to the basic expression.
   * This field is mainly used to pass context such a case description, long textual query or any other form of text that might help in
   * refining the query.
   */
  lq?: string;
  /**
   * The disjunction query expression.<br/>
   * This is the disjunctive part of the query expression that is merged with the other expression parts using an OR boolean operator.<br/>
   * When specified, the final expression evaluated by the index ends up being (q aq cq) OR (dq).
   */
  dq?: string;
  /**
   * The hub value set from the {@link Analytics} component.<br/>
   * Used for analytics reporting in the Coveo platform
   */
  searchHub?: string;
  /**
   * The tab value set from the {@link Tab} component.
   */
  tab?: string;
  locale?: string;
  /**
   * Name of the query pipeline to use.<br/>
   * Specifies the name of the query pipeline to use for the query. If not specified, the default value is default, which means the default query pipeline will be used.
   */
  pipeline?: string;
  /**
   * The maximum age for cached query results, in milliseconds.<br/>
   * If results for the exact same request (including user identities) are available in the in-memory cache, they will be used if they are not older than the specified value.<br/>
   * Otherwise, the query will be sent to the index.
   */
  maximumAge?: number;
  /**
   * Whether to enable wildcards on the basic expression keywords.<br/>
   * This enables the wildcard features of the index. Coveo Platform will expand keywords containing wildcard characters to the possible matching keywords to broaden the query.<br/>
   * See [Using Wildcards in Queries](https://docs.coveo.com/en/1580/).<br/>
   * If not specified, this parameter defaults to false.
   */
  wildcards?: boolean;
  /**
   * Whether to enable question marks with wildcards.<br/>
   * This enables using the question mark ? character within wildcard expressions.
   */
  questionMark?: boolean;
  /**
   * Whether to enable the support for operator in lowercase (AND OR -> and or)
   */
  lowercaseOperators?: boolean;
  /**
   * Whether to enable partial matching of the basic expression keywords.<br/>
   * By activating this, when the basic expression contains at least {@link IQuery.partialMatchKeywords}, items containing only the number of keywords specified by {@link IQuery.partialMatchThreshold} will also match the query.<br/>
   * Without this option, items are required to contain all the keywords in order to match the query.<br/>
   * If not specified, this parameter defaults to false.
   */
  partialMatch?: boolean;
  /**
   * The minimum number of keywords needed to activate partial match.<br/>
   * Specifies the minimum number of keywords needed for the partial match feature to activate.<br/>
   * If the basic expression contains less than this number of keywords, no transformation is applied on the query.<br/>
   * If not specified, this parameter defaults to 5.
   */
  partialMatchKeywords?: number;
  /**
   * The threshold to use for matching items when partial match is enabled.<br/>
   * Specifies the minimum number of query keywords that an item must contain when partial match is enabled. This value can either be an absolute number or a percentage value based on the total number of keywords.<br/>
   * If not specified, this parameter defaults to 50%.
   */
  partialMatchThreshold?: string;
  /**
   * This is the 0-based index of the first result to return.<br/>
   * If not specified, this parameter defaults to 0.
   */
  firstResult?: number;
  /**
   * This is the number of results to return, starting from {@link IQuery.firstResult}.<br/>
   * If not specified, this parameter defaults to 10.
   */
  numberOfResults?: number;
  /**
   * Specifies the sort criterion(s) to use to sort results. If not specified, this parameter defaults to Relevancy.<br/>
   * Possible values are : <br/>
   * -- relevancy :  This uses all the configured ranking weights as well as any specified ranking expressions to rank results.<br/>
   * -- dateascending / datedescending : Sort using the value of the @date field, which is typically the last modification date of an item in the index.<br/>
   * -- qre : Sort using only the weights applied through ranking expressions. This is much like using Relevancy except that automatic weights based on keyword proximity etc, are not computed.<br/>
   * -- nosort : Do not sort the results. The order in which items are returned is essentially random.<br/>
   * -- @field ascending / @field descending : Sort using the value of a custom field.
   */
  sortCriteria?: string;
  sortField?: string;
  /**
   * Specifies a field on which {@link Folding} should be performed.<br/>
   * Folding is a kind of duplicate filtering where only the first result with any given value of the field is included in the result set.<br/>
   * It's typically used to return only one result in a conversation, for example when forum posts in a thread are indexed as separate items.
   */
  filterField?: string;
  /**
   * Number of results that should be folded, using the {@link IQuery.filterField}
   */
  filterFieldRange?: number;
  /**
   * Specifies an array of fields that should be returned for each result.<br/>
   * eg: ['@foo','@bar']
   *
   */
  fieldsToInclude?: string[];
  /**
   * Specifies an array of fields that should be excluded from the query results.<br/>
   * eg: ['@foo','@bar']
   *
   */
  fieldsToExclude?: string[];
  /**
   * Specifies the length (in number of characters) of the excerpts generated by the indexer based on the keywords present in the query.<br/>
   * The index includes the top most interesting sentences (in the order they appear in the item) that fit in the specified number of characters.<br/>
   * When not specified, the default value is 200.
   */
  excerptLength?: number;
  /**
   * Specifies whether the first sentences of the item should be included in the results.<br/>
   * The retrieveFirstSentences option is typically used instead of excerpts when displaying email items, where the first sentence of the email might be of more interest than a contextually generated excerpt.
   */
  retrieveFirstSentences?: boolean;
  /**
   * This enables the query correction feature of the index.<br/>
   * By activating this, the index returns an array of {link IQueryCorrection} with suggested word corrections.
   */
  enableDidYouMean?: boolean;
  /**
   * Specifies an array of Query Function operation that will be executed on the results.
   */
  queryFunctions?: IQueryFunction[];
  /**
   * Specifies an array of Ranking Function operations that will be executed on the result
   */
  rankingFunctions?: IRankingFunction[];
  /**
   * Specifies an array of Group By operations that can be performed on the query results to extract facets
   */
  groupBy?: IGroupByRequest[];
  /**
   * Specifies an array of request to retrieve facet values for the CategoryFacet component
   */
  categoryFacets?: ICategoryFacetRequest[];
  /**
   * Whether to include debug information from the Search API in the query response.
   *
   * **Note:**
   * > This debug information does not include ranking information.
   *
   * Setting this property to `true` can have an adverse effect on query performance, so it should always be left to
   * `false` in a production environment.
   */
  debug?: boolean;
  timezone?: string;
  /**
   * Whether to enable the special query syntax such as field references for the basic query expression (parameter q).
   * It is equivalent to a No syntax block applied to the basic query expression.
   * If not specified, the parameter defaults to false
   */
  enableQuerySyntax?: boolean;
  enableDuplicateFiltering?: boolean;
  /**
   * Whether the index should take collaborative rating in account when ranking result. See: {@link ResultRating}
   */
  enableCollaborativeRating?: boolean;
  /**
   * Specifies the childField when doing parent-child loading (See: {@link Folding})
   */
  childField?: string;
  /**
   * Specifies the parentField when doing parent-child loading (See: {@link Folding})
   */
  parentField?: string;
  /**
   * The context is a map of key_value that can be used in the Query pipeline in the Coveo platform.<br/>
   */
  context?: Context;

  /**
   * The actions history represents the past actions a user made and is used by the Coveo Machine Learning service to
   * suggest recommendations. It is generated by the page view script (https://github.com/coveo/coveo.analytics.js)
   */
  actionsHistory?: string;

  /**
   * This is the id of the recommendation interface that generated the query.
   */
  recommendation?: string;

  /**
   * Specifies if the Search API should perform queries even when no keywords were entered by the end user.
   *
   * End user keywords are present in either the {@link IQuery.q} or {@link IQuery.lq} part of the query.
   *
   * This parameter is normally controlled by {@link SearchInterface.options.allowEmptyQuery} option.
   */
  allowQueriesWithoutKeywords?: boolean;

  /**
   * Specifies an array of request to retrieve facet values for the DynamicFacet component.
   */
  facets?: IFacetRequest[];

  /**
   * The global configuration options to apply to the requests in the [facets]{@link IQuery.facets} array.
   */
  facetOptions?: IFacetOptions;

  /**
   * The user ID or visitor ID whose item views should be tagged in the query results
   * (see the [isUserActionView]{@link IQueryResult.isUserActionView} property of the [IQueryResult]{@link IQueryResult} interface).
   *
   * **Examples:**
   *  - asmith@example.com
   *  - 6318b0c6-9397-4d70-b393-cf4770fd1bab
   */
  userActions?: IUserActionsRequest;
  /**
   * The commerce request to execute.
   */
  commerce?: ICommerceRequest;
  /**
   * The format of a successful response.
   * If not specified, this parameter defaults to 'json'.
   */
  format?: ResponseFormat;
}
