import { Capabilities } from './capabilities'
import { FieldSpec } from './field'
import { OrderSpec } from './order'
import { PagingMode } from './pagingMode'
import { SchemaPlugins } from './plugins'

/**
 * @interface Schema
 * @member displayName {string} - Defines UI-friendly name of a collection.
 * @member namespace {string} - Defines to which namespace the collections belongs to.
 * This is used for grouping collections in the editor's left side menu under Database section.
 * @member displayNamespace {string} - Defines a UI-friendly namespace value.
 * @member isDeleted {boolean} - Marks the schema as deleted and unavailable for use in data operations.
 * @member id {string} - ID should be formed by concatenating namespace, slash ('/') and collection name. For example:
 * 'Stores/Products'. This is the property that is used in Wix Data requests to refer to the collection. For example:
 * wixData.query('Stores/Products').find()
 * @member ownerAppId {string} - Id of app that exposes the schema. The collection will only be visible in sites
 * that have an application with the given id provisioned.
 * @member allowedOperations {Array<string>} - Lists Wix Data operations that are allowed in a given collection.
 * Operations that are not available will be hidden in Content Manager, Permissions dialog and Dataset options.
 * Wix Data however will not reject any operation performed by user from code. It is up for the driver to do so. It
 * is recommended to reject with a meaningful error message explaining why the operation did not succeed.
 * Returning empty array would block all filter options, returning null would allow options default for that type.
 * @member permissions - see {@link Permissions}
 * @member dataPermissions - general collection permission configuration (read-only)
 * @member allowedPermissions - allowed data operations for current user, included only on-demand, see {@link AllowedDataPermissions}
 * @member defaultSort {OrderSpec} - Denotes default sort of database if no sort is applied. This is used to communicate
 * to the user what the sort order is, if no sort order is specified. This should be set only if default sort order
 * exists for you collection as this is not the default order that will be passed down to find, but the order the
 * driver applies when no order is given.
 * @member displayField marks a field value of which will be used to represent the item in (multi-)references.
 * When showing assigned (multi-)references Content Manager will use this field to display which items are assigned.
 * When assigning new (multi-)reference item, this field can be used to search for the item.
 * @member fields { [fieldName: string]: FieldSpec } - Fields specifications.
 * @member maxPageSize {string} - Defines a maximum page size of a query supported by schema. Defaults are defined in DefaultMaxPageSize.
 * @member storage - see {@link Storage}
 * @member plugins - a map of plugins enabled for schema.
 * @member version {number} - When Optimistic Locking is enabled, the version number is defined and increments on
 * every schema change.
 * @member ttl - number of seconds this schema can be safely cached for. We suggest a high number for schemas that are
 * static in nature (that is user can not change them) and low number for those that can change. Schemas have little impact
 * to data operations in a live, so it is safe to cache even schemas that change because of user actions; only exceptions are
 * references and field deletion. Schemas are not cached in Editor segment.
 * @member capabilities - see {@link Capabilities}
 */
export interface Schema {
  displayName: string
  namespace?: string | null
  displayNamespace?: string | null
  isDeleted?: boolean
  id: string
  ownerAppId?: string | null
  allowedOperations?: DataOperation[]
  collectionOperations?: CollectionOperation[]
  permissions: Permissions | any // Allow for non-build breaking migration
  dataPermissions?: DataPermissions
  allowedPermissions?: AllowedDataPermissions
  defaultSort?: OrderSpec | null
  displayField?: string
  fields: { [fieldName: string]: FieldSpec }
  maxPageSize?: number
  storage?: Storage
  plugins?: SchemaPlugins
  version?: number
  ttl?: number | null
  pagingMode?: PagingMode[]
  capabilities?: Capabilities
}

/**
 * @member ownerAppId - required in DB driver schemas, see {@link Schema} for more details.
 */
export interface DbDriverSchema extends Schema {
  ownerAppId: string,
  namespace: string
}

export enum DataOperation {
  aggregate = 'aggregate',
  bulkInsert = 'bulkInsert',
  bulkRemove = 'bulkRemove',
  bulkSave = 'bulkSave',
  bulkUpdate = 'bulkUpdate',
  count = 'count',
  distinct = 'distinct',
  find = 'find',
  get = 'get',
  insert = 'insert',
  insertReference = 'insertReference',
  isReferenced = 'isReferenced',
  queryReferenced = 'queryReferenced',
  remove = 'remove',
  removeReference = 'removeReference',
  replaceReferences = 'replaceReferences',
  save = 'save',
  truncate = 'truncate',
  update = 'update',
  patch = 'patch',
  bulkPatch = 'bulkPatch'
}

export enum CollectionOperation {
  UPDATE = 'update',
  REMOVE = 'remove'
}

/**
 * Defines permissions to be shown in Content Manager. User
 * will see a read only list of permissions applied. The items
 * displayed are determined from allowedOperations and the
 * values are specified in this data structure.
 *
 * @deprecated use allowedPermissions to check current user or data permission service to configure permissions
 */
export interface Permissions {
  read?: PermissionRole
  update?: PermissionRole
  insert?: PermissionRole
  remove?: PermissionRole
}

export enum PermissionRole {
  /**
   * Anyone (anonymous) can perform the operation
   */
  anyone = 'anyone',

  /**
   * User of user can perform the operation
   */
  siteMember = 'siteMember',

  /**
   * User of user who is the owner (producer) of the
   * data can perform the operation.
   *
   * In regular Wix Data collections, this allows
   * performing operation on an item if _owner field
   * matches the currently logged Site Member id.
   *
   * In case of DB drivers, this can match the
   * ownership that is appropriate to vertical, ex.:
   * UoU can see his purchases, or contact can see
   * his details.
   */
  siteMemberAuthor = 'siteMemberAuthor',

  /**
   * Site Admin can perform the operation.
   */
  admin = 'admin'
}

export interface DataPermissions {
  itemRead: AccessLevel
  itemInsert: AccessLevel
  itemUpdate: AccessLevel
  itemRemove: AccessLevel
}

export enum AccessLevel {
  /** Any subject, including visitors */
  ANYONE = 'ANYONE',

  /** Any signed-in user (both site members and collaborators) */
  SITE_MEMBER = 'SITE_MEMBER',

  /** Any signed-in user, but site members only have access to own items */
  SITE_MEMBER_AUTHOR = 'SITE_MEMBER_AUTHOR',

  /** Site collaborator that has a role with CMS Access permission */
  CMS_EDITOR = 'CMS_EDITOR',

  /** CMS administrators and users or roles granted with special access */
  PRIVILEGED = 'PRIVILEGED'
}

/**
 * Defines actual allowed data operations
 */
export interface AllowedDataPermissions {
  itemRead: boolean
  itemInsert: boolean
  itemUpdate: boolean
  itemRemove: boolean
}

export enum Storage {
  /**
   * DB driver collection
   */
  driver = 'driver',

  /**
   * User collection
   */
  docstore = 'docstore',

  /**
   * App builder collection
   * @deprecated
   * `Storage.staticAppSchema` should be used instead
   */
  app = 'app',

  /**
   * External db driver collection
   */
  external = 'external',

  /**
   * Dynamic application collection. For example Forms collection.
   * @deprecated
   * `Storage.driver` should be used instead
   */
  dynamicApplication = 'dynamicApplication',

  /**
   * Static application collection. For example Blocks collection.
   */
  staticAppSchema = 'staticAppSchema'
}
