import type Accessor from "../../core/Accessor.js";
import type SpatialReference from "../../geometry/SpatialReference.js";
import type InputQuantizationParameters from "./InputQuantizationParameters.js";
import type { ValidBindParameterType } from "./types.js";

export interface ReplicaDefinitionProperties extends Partial<Pick<ReplicaDefinition, "creationDate" | "lastSyncDate" | "replicaFilters" | "replicaId" | "replicaName" | "replicaOwner" | "syncDirection">> {}

/**
 * A replica definition returned from a knowledge graph replica endpoint.
 *
 * @since 5.1
 */
export default class ReplicaDefinition extends Accessor {
  constructor(properties?: ReplicaDefinitionProperties);
  /** Date the replica was created. */
  accessor creationDate: Date | null | undefined;
  /** Date of the last replica sync. */
  accessor lastSyncDate: Date | null | undefined;
  /** Filters that define the replica scope. */
  accessor replicaFilters: ReplicaFilters | null | undefined;
  /** Unique identifier of the replica. */
  accessor replicaId: string | null | undefined;
  /** Name of the replica. */
  accessor replicaName: string | null | undefined;
  /** Owner of the replica. */
  accessor replicaOwner: string | null | undefined;
  /** Synchronization direction for the replica. */
  accessor syncDirection: ReplicaSyncDirection | null | undefined;
}

export interface ReplicaReference {}

export type ReplicaProvenanceOptions = {
    includeProvenance: true;
    includeSourceDocuments?: boolean;
} | { includeProvenance: false; };

export type ReplicaDocumentOptions = {
    includeConnectedDocuments: true;
    includeDocumentProvenance: true;
    includeDocumentSourceDocuments?: boolean;
} | {
    includeConnectedDocuments: true;
    includeDocumentProvenance?: false;
} | { includeConnectedDocuments: false; };

/**
 * Entity type and relationship type definitions included in the replica definition.
 *
 * At least one of [entityTypeReplicaDefinitions](#entityTypeReplicaDefinitions) or [relationshipTypeReplicaDefinitions](#relationshipTypeReplicaDefinitions)
 * must be provided with at least one definition.
 */
export interface ReplicaNamedTypeDefinition {
  /** The entity type or relationship type name. */
  typeName: string;
  /** An openCypher where clause to filter the specific entities or relationships included in the replica. */
  openCypherWhereClause?: string;
  /** Options for specifying how provenance is included in the replica. */
  provenanceOptions?: ReplicaProvenanceOptions | null;
  /** Bind parameters to send with the openCypher query to define the replica. */
  parameters?: Record<string, ValidBindParameterType> | null;
}

/**
 * Entity type definitions included in the replica static definition.
 *
 * At least one of `entityTypeReplicaDefinitions` or `relationshipTypeReplicaDefinitions`
 * must be provided with at least one definition.
 */
export interface ReplicaEntityTypeDefinition extends ReplicaNamedTypeDefinition {}

/**
 * Relationship type definitions included in the replica static definition.
 *
 * At least one of `entityTypeReplicaDefinitions` or `relationshipTypeReplicaDefinitions`
 * must be provided with at least one definition.
 */
export interface ReplicaRelationshipTypeDefinition extends ReplicaNamedTypeDefinition {}

/** The definition of a replica including the entity types and relationship types to be included. Additional filters can be applied to each type to get a subset of data. */
export interface ReplicaStaticDefinition {
  /**
   * Entity type definitions included in the replica static definition.
   *
   * At least one of `entityTypeReplicaDefinitions` or `relationshipTypeReplicaDefinitions`
   * must be provided with at least one definition.
   */
  entityTypeReplicaDefinitions?: ReplicaEntityTypeDefinition[] | null;
  /**
   * Relationship type definitions included in the replica static definition.
   *
   * At least one of `entityTypeReplicaDefinitions` or `relationshipTypeReplicaDefinitions`
   * must be provided with at least one definition.
   */
  relationshipTypeReplicaDefinitions?: ReplicaRelationshipTypeDefinition[] | null;
}

export interface ReplicaFilters {
  /**
   * Custom quantization parameters for input geometry that compresses geometry for transfer to the server.
   * Overrides the default lossless WGS84 quantization.
   */
  inputQuantizationParameters?: InputQuantizationParameters | null;
  /** Custom spatial reference for input geometry. */
  inputSpatialReference?: SpatialReference | null;
  /** The definition of a replica including the entity types and relationship types to be included. Additional filters can be applied to each type to get a subset of data. */
  staticDefinition: ReplicaStaticDefinition;
}

export type ReplicaSyncDirection = "bidirectional" | "upload" | "download";

export type ReplicaSyncDataFormat = "pbf" | "spbf" | "geoparquet" | "sqlite";

/** Base options shared by replica create request variants. */
export interface BaseReplicaOptions {
  /** Requested name to use when creating the replica. */
  requestedReplicaName: string;
  /** Optional requested replica id in UUID string format. */
  requestedReplicaId?: string;
  /** Synchronization direction for the replica operation. */
  syncDirection: ReplicaSyncDirection;
  /** Data format to use for replica synchronization payloads. */
  syncDataFormat: ReplicaSyncDataFormat;
  /** The type of the replica creation options. */
  type: "reference" | "filter";
}

/** Additional options used by [executeCreateReplica()](https://developers.arcgis.com/javascript/latest/references/core/rest/knowledgeGraphService/#executeCreateReplica) for reference replica creation. */
export interface ReferenceReplicaOptions extends BaseReplicaOptions {
  /** Reference replica used as a create baseline. */
  referenceReplica: ReplicaReference;
  /** The type of the replica creation options. */
  type: "reference";
}

/** Additional options used by [executeCreateReplica()](https://developers.arcgis.com/javascript/latest/references/core/rest/knowledgeGraphService/#executeCreateReplica) for filtered replica creation. */
export interface FilterReplicaOptions extends BaseReplicaOptions {
  /** filters to define the replica scope. */
  replicaFilters: ReplicaFilters;
  /** The type of the replica creation options. */
  type: "filter";
}