import { FieldPlugins } from './fieldPlugins'

/**
 * @interface FieldSpec
 * @member displayName {string} - Defines UI-friendly name of a field. This name is used in Content Manager
 * header and when binding to the field in Data Binding.
 * @member type {FieldType} - Defines field data type.
 * @member systemField {boolean} - Defines field is system or user created field.
 * @member queryOperators {Array<AllowedFilterOperator>} - Denotes which filter operators can be used on field. This limits
 * the filters that are available in Content Manager and Dataset. Wix Data, however, will not validate filters
 * passed by user from code. Undefined implies default type operators are supported, empty array - no filters
 * are supported on the field.
 * @member sortable {boolean} - Defines the field is sortable or not. Similarly to queryOperators, impacts
 * Content Manager and Data Binding.
 * @member isDeleted {boolean} - Deleted fields are hidden from data results, also excluded from sorts
 * and filters.
 * @member index {number} - Defines field order in cases where fields are ordered, e.g., Content Manager.
 * @member pii {boolean} - Indicates that field contains PII data and should be encrypted.
 * @member calculator {Calculator} - Defines how virtual data should be generated.
 * @member linkedRouterPage {string} - Defines reference to router pattern in the site document
 * @member minValue {number} - Min possible value for the field.
 * @member maxValue {number} - Max possible value for the field.
 * @member minStrLength {number} - Min length for the string field.
 * @member maxStrLength {number} - Max length for the string field.
 * @member minArraySize {number} - Min size for the repeated field.
 * @member maxArraySize {number} - Max size for the repeated field.
 * @member readOnly {boolean} - Indicates that the field cannot be set by the client. E.g. Id field assigned by the server.
 * @member immutable {boolean} - Indicates that the field can be set by the client, but can never be changed or updated.
 * @member required {boolean} - Indicates that the field is required.
 */
export type FieldSpec = {
  displayName: string
  type: FieldType
  systemField: boolean
  queryOperators?: AllowedFilterOperator[]
  sortable?: boolean
  isDeleted?: boolean
  index?: number
  pii?: boolean
  calculator?: Calculator
  linkedRouterPage?: string
  description?: string
  minValue?: number
  maxValue?: number
  minStrLength?: number
  maxStrLength?: number
  minArraySize?: number
  maxArraySize?: number
  readOnly?: boolean
  immutable?: boolean
  required?: boolean
  plugin?: string
  plugins?: FieldPlugins
  pageLinkType?: PageLinkType
  condition?: Condition
} & ValidFieldTypes

export type NestedFieldSpec = {
  type: FieldType
  displayName?: string
  queryOperators?: AllowedFilterOperator[]
  sortable?: boolean
} & ValidNestedFieldTypes

export type ValidFieldTypes = ReferenceField | MultiReferenceField | ValidNestedFieldTypes | SlugField

export type ValidNestedFieldTypes = TextField | NumberField | DateTimeField | DateField | ImageField | BoolField | DocumentField | UrlField | EmailField |
  RichTextField | VideoField | PageLinkField | MediaGalleryField | AddressField | AnyField | ArrayStringField | ArrayDocumentField |
  AudioField | TimeField | LanguageField | RichContentField | ColorField | ArrayField | ObjectField

export interface Calculator {
  config: {
    pattern: string,
    lowercase: boolean
  }
}

export enum FieldType {
  /**
   * JSON Number (Ex. 2 or 26.7)
   */
  number = 'number',

  /**
   * JSON String
   */
  text = 'text',

  /**
   * Wix Media or HTTP(S) url to an image,
   * image://...
   */
  image = 'image',

  /**
   * JSON Boolean (true, false)
   */
  boolean = 'boolean',

  /**
   * Wix Media link to a document, in form wix:media://...
   */
  document = 'document',

  /**
   * HTTP(S) URL as a JSON String
   */
  url = 'url',

  /**
   * Email address as a JSON String
   */
  email = 'email',

  /**
   * HTML String with tags allowed in Wix RichText.
   */
  richText = 'richtext',

  /**
   * Date type represented as an object with $date attribute
   * holding ISO 8601 string with UTC date.
   *
   * Example: { $date: '2018-04-01T00:00:00Z' }
   *
   * This will get transformed to JavaScript Date on the client side.
   * It is similar to 'dateTime', except for the time part:
   * time always is 00:00:00Z
   */
   date = 'date',

  /**
   * Date time type represented as an object with $date attribute
   * holding ISO 8601 string with UTC date.
   *
   * Example: { $date: '2018-04-01T00:00:00Z' }
   *
   * This will get transformed to JavaScript Date on the client side.
   */
  dateTime = 'datetime',

  /**
   * Wix Media link to video
   */
  video = 'video',

  /**
   * String ID to referenced item.
   *
   * If specified in a collection together with referencedCollectionName,
   * Wix Data will handle the includes by making additional request to
   * included collection using hasSome filter and passing down ids of the
   * items to be included.
   */
  reference = 'reference',

  /**
   * Multi-reference fields are not yet directly supported in DB Drivers.
   * Consult Wix Data team before trying to use it.
   */
  multiReference = 'multi-reference',

  /**
   * Relative URL to a page in a site.
   */
  pageLink = 'pagelink',

  /**
   * JSON Object as plain JSON.
   */
  object = 'object',

  /**
   * Gallery type for binding to Pro Gallery components.
   */
  mediaGallery = 'media-gallery',

  /**
   * Address type.
   * See https://docs.google.com/document/d/1pwZKxnBBxR1mBnJGiS6M6qSdjKd1YDJ2OAM4nHJjFS8/edit#heading=h.5ndfgx3b0knm
   *
   * Items should at very least contain 'formatted' property.
   */
  address = 'address',

  /**
   * Array of strings type.
   */
  stringArray = 'array<string>',

  /**
   * JSON Color Hex String
   */
  color = 'color',

  /**
   * Wix Media link to audio
   */
  audio = 'audio',

  /**
   * JSON String holding time in a following format: '00:00:00'
   */
  time = 'time',

  /**
   * Array
   */
  array = 'array',

  /**
   * RichContent type for binding to RichContentEditor/RichContentViewer components
   * based on Ricos https://github.com/wix-incubator/rich-content
   */
  richContent = 'rich-content',

  /**
   * Text string holding language name in which row content is translated. Complies with BCP47 standard: https://tools.ietf.org/html/bcp47#appendix-A
   */
  language = 'language',

  /**
   * Array of documents, see {@link FieldType.document}
   */
  documentArray = 'array<document>',

  /**
   * Any JSON data type
   */
  any = 'any',

  /**
   * Slug type used for dynamic page URLs.
   */
  slug = 'slug',

  legacyBook = 'bookType',

  legacyExternalUrl = 'externalUrl',

  legacyBrokenRef = 'broken-reference',

  legacyExternalVideo = 'externalVideo',

  legacyImage = 'Image'
}

export type TextField = { type: FieldType.text }
export type NumberField = { type: FieldType.number }
export type DateTimeField = { type: FieldType.dateTime }
export type DateField = { type: FieldType.date }
export type ImageField = { type: FieldType.image }
export type BoolField = { type: FieldType.boolean }
export type DocumentField = { type: FieldType.document }
export type UrlField = { type: FieldType.url }
export type EmailField = { type: FieldType.email }
export type RichTextField = { type: FieldType.richText }
export type VideoField = { type: FieldType.video }
export type PageLinkField = { type: FieldType.pageLink }
export type MediaGalleryField = { type: FieldType.mediaGallery }
export type AddressField = { type: FieldType.address }
export type AnyField = { type: FieldType.any }
export type ArrayStringField = { type: FieldType.stringArray }
export type ArrayDocumentField = { type: FieldType.documentArray }
export type AudioField = { type: FieldType.audio }
export type TimeField = { type: FieldType.time }
export type LanguageField = { type: FieldType.language }
export type RichContentField = { type: FieldType.richContent }
export type ColorField = { type: FieldType.color }

/**
 * @member referencedCollection {string} - Denotes referenced collection name.
 */
export type ReferenceField = {
  type: FieldType.reference
  referencedCollection: string
}

/**
 * @member referencedCollection {string} - Denotes referenced collection name.
 * @member referencingFieldKey {string} - Denotes the field key to represent current collection items
 * in referenced collection.
 * @member referencingDisplayName {string} - Defines UI-friendly name for field that represents current
 * collection items in referenced collection. This name is used in Content Manager header and when
 * binding to the field in Data Binding.
 */
export type MultiReferenceField = {
  type: FieldType.multiReference
  referencedCollection: string
  referencingFieldKey: string
  referencingDisplayName?: string
}

/**
 * @member elementType {NestedFieldSpec} - Denotes type of elements in array.
 */
export type ArrayField = {
  type: FieldType.array,
  elementType?: ValidNestedFieldTypes
}

/**
 * @member elementType { [fieldName: string]: NestedFieldSpec } - Denotes structure of the the object.
 */
export type ObjectField = {
  type: FieldType.object,
  fields?: { [fieldName: string]: NestedFieldSpec }
}

/**
 * @member pattern {string} - Denotes pattern for generating slug values.
 */
export type SlugField = {
  type: FieldType.slug,
  pattern: string
}

export enum AllowedFilterOperator {
  eq = 'eq',
  ne = 'ne',
  lt = 'lt',
  lte = 'lte',
  gt = 'gt',
  gte = 'gte',
  hasSome = 'hasSome',
  hasAll = 'hasAll',
  contains = 'contains',
  startsWith = 'startsWith',
  endsWith = 'endsWith',
  urlized = 'urlized',
  exists = 'exists'
}

export enum PageLinkType {
  COLLECTION_DEFINED = 'COLLECTION_DEFINED',
  ROUTER_DEFINED = 'ROUTER_DEFINED'
}

export enum FieldPermission {
  /** No special permissions required to read the field (visitors) */
  ANYONE,

  /**
   * Special permissions required to read the field (members, contributors, etc.)
   */
  RESTRICTED,
}

export type Condition = {
  /** Conditional (requested) field enum value */
  groupName?: string

  /** Who can read the field? */
  permission: FieldPermission
}
