import type { GraphJson } from '@api-client/graph/graph/types.js'
import type { Graph } from '@api-client/graph/graph/Graph.js'
import type { DomainAssociation } from './DomainAssociation.js'
import type { DomainEntity } from './DomainEntity.js'
import type { DomainModel } from './DomainModel.js'
import type { DomainNamespace } from './DomainNamespace.js'
import type { DomainProperty } from './DomainProperty.js'

export interface DataDomainRemoveOptions {
  /**
   * When true, the object will be forcibly removed.
   * The resolution defined in the `ImpactResolution` class will be applied.
   *
   * For example, when removing an entity that is a parent to another entity, it will
   * removed itself as a parent from the child entity.
   *
   * Note, this option should only be used when the DomainImpactAnalysis has been performed
   * and the user was informed of the impact.
   */
  force?: boolean
}

export interface AssociationAddOptions {
  /**
   * When set, it is the the association target's origin data domain.
   * The key of the target data domain where this target entity is defined.
   * Only used when `key` is specified.
   */
  domain?: string
  /**
   * The key of the association target, if known.
   * If the target of the association is not specified, and the association has no other targets,
   * the association is ignored in the namespace while processing.
   */
  key?: string
}

export interface DomainGraphEdge {
  /**
   * Indicates that the edge is to or from a foreign domain.
   */
  foreign?: boolean
  /**
   * The key of the foreign domain. Always set with the `foreign` property.
   */
  domain?: string
  /**
   * The type of the edge.
   * - `association` The edge is to an association object.
   *   - When coming **from** an entiry (the `v` property), that entity owns the association.
   *   - When coming **to** an entity (the `w` property), that entity is the target of the association.
   *     An association can have multiple targets.
   * - `property` The edge is to a property object. Can only be created between an entity and a property.
   *   - The **from** (`v`) is the entity.
   *   - The **to** (`w`) is the property.
   * - `parent` The edge is to a parent object.
   *   - The **from** (`v`) is the child entity.
   *   - The **to** (`w`) is the parent entity.
   */
  type: 'association' | 'property' | 'parent'
}

export type DomainGraphNodeType = DomainNamespace | DomainModel | DomainEntity | DomainProperty | DomainAssociation

/**
 * An interface that describes the data domain dependency.
 */
export interface ForeignDomainDependency {
  /**
   * The system registered key of the foreign domain.
   */
  key: string
  /**
   * The version of the foreign domain used in this domain.
   */
  version: string
}

export interface AssociationTarget {
  /**
   * The key of the target entity.
   */
  key: string
  /**
   * The key of the target data domain.
   * This is only set when the target is in a different data domain.
   */
  domain?: string
}

/**
 * Describes the default value set on a property schema.
 */
export interface SchemaDefaultValue {
  /**
   * The type of the default value.
   *
   * - `literal` The `value` should be used as-is.
   * - `function` The value represents the name of the function to be used.
   */
  type: 'literal' | 'function'
  /**
   * The actual value type depends on the `type`.
   * It is always a string and it has to be casted to the property's data type.
   */
  value: string
}

/**
 * A general schema definition for a property.
 * This is propagated to all bindings (when they support these properties).
 */
export interface PropertySchema {
  /**
   * The minimum value of the property.
   *
   * By default it is inclusive value. Use the `exclusiveMinimum` property to make it exclusive.
   *
   * Used with:
   * - string
   * - number
   * - date
   * - time
   * - datetime
   */
  minimum?: number
  /**
   * The maximum value of the property.
   *
   * By default it is inclusive value. Use the `exclusiveMaximum` property to make it exclusive.
   *
   * Used with:
   * - string
   * - number
   * - date
   * - time
   * - datetime
   */
  maximum?: number
  /**
   * When set, the minimum value is exclusive.
   *
   * - When `false`: value ≥ minimum.
   * - When `true`: value > minimum.
   */
  exclusiveMinimum?: boolean
  /**
   * When set, the exclusiveMaximum value is exclusive.
   *
   * - When `false`: value ≤ maximum.
   * - When `true`: value < minimum.
   */
  exclusiveMaximum?: boolean
  /**
   * The multiplier value for a number scalar.
   *
   * Examples:
   * - if `1` then every integer is allowed
   * - if `2` than every even number is allowed
   * - if `0.5` than every number dividable by `0.5` is allowed
   */
  multipleOf?: number
  /**
   * The enum values for the property.
   * They are always encoded as strings. The actual type is defined in the `dataType` property.
   */
  enum?: string[]
  /**
   * The default value for the property.
   * This is always encoded as a string. The actual type is defined in the `dataType` property.
   */
  defaultValue?: SchemaDefaultValue
  /**
   * The example values for the property.
   * They are always encoded as strings. The actual type is defined in the `dataType` property.
   */
  examples?: string[]
}

/**
 * The shortcut type for the data domain graph.
 */
export type DataDomainGraph = Graph<unknown, DomainGraphNodeType, DomainGraphEdge>
/**
 * The serialized version of the data domain graph.
 */
export type SerializedGraph = GraphJson<unknown, object, DomainGraphEdge>
