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'
import type {
  DomainNamespaceKind,
  DomainEntityKind,
  DomainModelKind,
  DomainPropertyKind,
  DomainAssociationKind,
  DataDomainKind,
  ExposedEntityKind,
} from '../models/kinds.js'
import type { DataDomain } from './DataDomain.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 entity (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 pattern to use with a string scalar.
   */
  pattern?: 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>

/**
 * Represents a standardized, machine-readable error response body
 * as defined by RFC 7807 for HTTP APIs.
 */
export interface ProblemDetails {
  /**
   * A URI that identifies the specific problem type. Should resolve to human-readable docs.
   * e.g., "https://docs.apinow.app/errors/validation-failed"
   */
  type: string

  /**
   * A short, human-readable summary of the problem type.
   * e.g., "Validation Error"
   */
  title: string

  /**
   * The HTTP status code generated by the origin server for this problem.
   */
  status?: number

  /**
   * A human-readable explanation specific to this occurrence of the problem.
   */
  detail?: string

  /**
   * A URI that identifies the specific occurrence of the problem.
   * Can be the API request path that caused the error.
   */
  instance: string
}

/**
 * The set of supported filter operators for the List action.
 * These are used in query parameters, e.g., ?price[gte]=100
 *
 * - eq: Equal
 * - nq: Not Equal
 * - lt: Less Than
 * - lte: Less Than or Equal
 * - gt: Greater Than
 * - gte: Greater Than or Equal
 * - ex: Checks if the field exists
 * - re: Regular expression match
 * - bf: Date before a specific value
 * - af: Date after a specific value
 * - cn: String contains substring / Array contains element
 * - st: String starts with
 * - end: String ends with
 * - in: Value is one of the elements in the provided array
 * - nin: Value is not one of the elements in the provided array
 */
export type ResourceFilterOperator =
  | 'eq' // Equal
  | 'nq' // Not equal
  | 'lt' // Less than
  | 'lte' // Less than or equal
  | 'gt' // Greater than
  | 'gte' // Greater than or equal
  | 'ex' // Checks if the field exists
  | 're' // Regular expression match
  | 'bf' // Date before a specific value
  | 'af' // Date after a specific value
  | 'cn' // String contains substring / Array contains element
  | 'st' // String starts with
  | 'end' // String ends with
  | 'in' // Value is one of the elements in the provided array
  | 'nin' // Value is not one of the elements in the provided array

/**
 * The session transport configuration interface.
 * This defines the properties that are common to all session transports.
 */
interface SessionTransport {
  /**
   * Whether the session transport is enabled.
   */
  enabled: boolean
  /**
   * The kind of session transport. Each interface defines its own kind.
   */
  kind: string
}

/**
 * Configuration for cookie-based session transport.
 */
export interface CookieConfiguration extends SessionTransport {
  kind: 'cookie'
  /**
   * The lifetime of the cookie session.
   * This is a string representing the duration, e.g., "7d" for 7 days or "24h" for 24 hours.
   *
   * @default "7d"
   */
  lifetime: string
  /**
   * Whether the cookie can only be accessed by the server.
   * This is a security feature to prevent client-side scripts from accessing the cookie.
   * If set to false, the cookie can be accessed by client-side scripts.
   * @default true
   */
  httpOnly: boolean // Defaults to true
  /**
   * Whether the cookie should only be sent over secure connections (HTTPS).
   * This is a security feature to prevent the cookie from being sent over unencrypted connections.
   * @default true
   */
  secure: boolean
  /**
   * The SameSite attribute of the cookie.
   * This attribute controls whether the cookie is sent with cross-site requests.
   * - 'none' means the cookie is sent with cross-site requests.
   * - 'lax' means the cookie is sent with top-level navigations and will be sent along with GET
   *   requests initiated by third-party websites.
   * @default 'none'
   */
  sameSite: 'none' | 'lax'
  /**
   * The name of the cookie.
   * This is the key under which the session data will be stored in the cookie.
   * @default 'as' - 'as' stands for "api session"
   */
  name: string
}

/**
 * Configuration for JWT-based session transport.
 */
export interface JwtConfiguration extends SessionTransport {
  kind: 'jwt'
  /**
   * The lifetime of the JWT token.
   * This is a string representing the duration, e.g., "7d" for 7 days or "15m" for 15 minutes.
   *
   * @default "7d"
   */
  lifetime: string
}

export interface SessionConfiguration {
  /**
   * The secret used to sign the JWT and cookies. Should be handled securely.
   * Not visible in the UI after being set.
   */
  secret: string
  /**
   * The properties from the `User` entity to be encoded into the session payload (JWT/cookie).
   * These properties become available in the `request.auth` object at runtime.
   *
   * In practice, these are the ids of the properties in the `User` entity.
   */
  properties: string[]
  /**
   * The cookie-based session transport configuration.
   */
  cookie?: CookieConfiguration

  /**
   * The JWT-based session transport configuration.
   */
  jwt?: JwtConfiguration
}

/**
 * Defines the authorization strategy for the API.
 * It is a base interface that can be extended for different strategies.
 * For MVP, we will start with Roles-Based Access Control (RBAC).
 */
export interface AuthorizationConfiguration {
  /**
   * The authorization strategy. For MVP, we will start with RBAC.
   * Post-MVP will include Permission-Based Access Control (PBAC).
   * The strategy determines how users are granted access to resources.
   *
   * - RBAC (Roles-Based Access Control): Users are assigned roles, and permissions are granted to those roles.
   * - PBAC (Permission-Based Access Control): Users are granted permissions directly, allowing for more
   *   granular control.
   */
  strategy: string
}

export interface RolesBasedAccessControl extends AuthorizationConfiguration {
  strategy: 'RBAC'
  /**
   * The property within the designated "User" entity that defines the user's role.
   * This field is used in access rules to grant permissions.
   *
   * This property must be marked with the "Role" data semantic in the Data Modeler.
   * It is required to publish the API.
   */
  roleKey: string
}

/**
 * Configures the strategy for authenticating end-users.
 * An API can only support one authentication strategy at a time.
 * This is a base interface that can be extended for different strategies.
 */
export interface AuthenticationConfiguration {
  /**
   * The authentication method. For MVP, this is focused on username/password.
   * This can be extended in the future to include 'SSO'.
   */
  strategy: string
}

/**
 * Configuration for username/password authentication.
 * This is the primary authentication method for the API (MVP).
 */
export interface UsernamePasswordConfiguration extends AuthenticationConfiguration {
  strategy: 'UsernamePassword'
  /**
   * The specific property within the User entity that holds the password.
   * This property must be marked with the "Password" data semantic in the Data Modeler.
   *
   * This property is required to publish the API.
   */
  passwordKey?: string
}

/**
 * Represents a Data Entity from the Data Domain that the API will expose and operate upon.
 */
export interface ExposedEntitySchema {
  kind: typeof ExposedEntityKind
  /**
   * The unique identifier for this exposure instance.
   * In the exposure model, we need to uniquely identify each exposure instance, because
   * an entity can be exposed multiple times in different contexts. Consider the following structure:
   *
   * ```
   * /categories/{categoryId}
   * /products/{productId}/categories
   * /products/{productId}/categories/{categoryId}
   * /promotions/{promotionId}/categories
   * /promotions/{promotionId}/categories/{categoryId}
   * ```
   *
   * The `category` entity would be exposed multiple times (as root and nested under products and promotions).
   * We need a way to distinguish between these different exposure instances.
   */
  key: string
  /**
   * A pointer to a Data Entity from the Data Domain.
   */
  entity: AssociationTarget
  /**
   * Indicates whether this exposure has a collection endpoint.
   * A collection endpoint is optional for nested exposures where the association is 1:1
   * and the schema is embedded directly under the parent resource.
   */
  hasCollection: boolean
  /**
   * A path to the collection endpoint for this exposure.
   * Starts with '/'. Not set for 1:1 nested exposures where collection does not exist.
   */
  collectionPath?: string

  /**
   * A path to the resource endpoint for this exposure.
   * Starts with '/'. For 1:1 nested exposures the resource path typically does not include an id segment.
   */
  resourcePath: string

  /**
   * Whether this exposure is a root exposure (top-level collection).
   * If this is set then the `parent` reference must be populated.
   */
  isRoot?: boolean

  /**
   * Parent reference when this exposure was created via following an association.
   */
  parent?: ExposeParentRef

  /**
   * Expose-time config used to create this exposure (persisted for auditing/UI).
   * This is only populated for the root exposure. All children exposures inherit this config.
   */
  exposeOptions?: ExposeOptions

  /**
   * The list of enabled API actions for this exposure (List/Read/Create/etc.)
   */
  actions: ApiAction[]

  /**
   * Optional array of access rules that define the access control policies for this exposure.
   */
  accessRule?: AccessRule[]

  /**
   * Optional configuration for rate limiting for this exposure.
   */
  rateLimiting?: RateLimitingConfiguration

  /**
   * When true, generation for this exposure hit configured limits
   */
  truncated?: boolean
}

/**
 * Parent reference stored on a nested exposure
 */
export interface ExposeParentRef {
  /**
   * The key of the parent exposed entity. This references the `ExposedEntity.key` property.
   */
  key: string
  /**
   * The association from the parent that produced this exposure.
   * A sub-entity must always have a parent association.
   */
  association: AssociationTarget
  /**
   * The numeric depth from the root exposure (root = 0)
   */
  depth?: number
}

/**
 * Options passed when creating a new exposure
 */
export interface ExposeOptions {
  /**
   * Whether to follow associations when creating the exposure.
   * When not set, it only exposes the passed entity.
   */
  followAssociations?: boolean
  /**
   * The maximum depth to follow associations when creating the exposure.
   */
  maxDepth?: number
}

/**
 * Represents a specific, configurable API operation applied to a Data Entity.
 * Corresponds to common RESTful interactions.
 */
export type ApiAction = ListAction | ReadAction | CreateAction | UpdateAction | DeleteAction | SearchAction

/**
 * A base interface for common properties across all actions.
 */
interface Action {
  /**
   * The specific kind of action (e.g., 'List', 'Read', etc.)
   */
  kind: string
  /**
   * Access control rules defining who can perform this action. It is only applied if the
   * authorization strategy is set to 'RBAC'.
   * If no rules grant access, it's denied by default making it essentially private.
   *
   * Note, the API can defined top level access rules that apply to all actions. If this property is set,
   * it overrides the top level access rules for this specific action.
   *
   * It is an ordered list, meaning the first rule that matches the user will be applied.
   * If multiple rules match, the first one in the list takes precedence.
   * If no rules match, the action is denied.
   */
  accessRule?: AccessRule[]
  /**
   * Optional configuration for action-wide rate limiting and throttling.
   * Defines rules to protect the action from overuse.
   */
  rateLimiting?: RateLimitingConfiguration
}

/**
 * Represents a pagination strategy for API actions that return collections of resources.
 * This is a base interface that can be extended for different pagination strategies.
 */
export interface PaginationStrategy {
  /**
   * The kind of pagination strategy. This is used to identify the specific pagination method.
   * For example, 'cursor' for cursor-based pagination or 'offset' for offset-based pagination.
   */
  kind: string
  /**
   * The default page size for the pagination strategy.
   * This is the number of items returned per page when no specific page size is requested.
   */
  pageSize?: number
}

/**
 * Represents the cursor-based pagination strategy.
 */
export interface CursorPaginationStrategy extends PaginationStrategy {
  kind: 'cursor'
}

/**
 * Represents the offset-based pagination strategy.
 */
export interface OffsetPaginationStrategy extends PaginationStrategy {
  kind: 'offset'
}

/**
 * Enables retrieving a collection of resources.
 * Endpoint: GET /[entity-collection-name]
 */
export interface ListAction extends Action {
  kind: 'list'
  /**
   * The pagination strategy used for this action.
   * This defines how the results are paginated when retrieving a collection of resources.
   * It can be either 'cursor' or 'offset'.
   */
  pagination: PaginationStrategy
  /**
   * Fields from the entity that can be used for filtering.
   * Must be marked as "indexable" in the Data Model.
   */
  filterableFields: string[]
  /**
   * Fields from the entity that can be used for sorting.
   */
  sortableFields: string[]
}

/**
 * Enables retrieving a single resource by its ID.
 * Endpoint: GET /[entity-collection-name]/{id}
 */
export interface ReadAction extends Action {
  kind: 'read'
  // Association handling (Link IDs vs. Embed) is defined on the
  // data association itself in the Data Modeler.
}

/**
 * Enables adding a new resource to a collection.
 * Endpoint: POST /[entity-collection-name]
 */
export interface CreateAction extends Action {
  kind: 'create'
}

/**
 * Enables modifying an existing resource.
 * Endpoints: PUT or PATCH /[entity-collection-name]/{id}
 */
export interface UpdateAction extends Action {
  kind: 'update'
  /**
   * The allowed HTTP methods for updates. Default: PATCH only.
   *
   * These two methods represent the two common ways to update a resource:
   * - PUT: Replaces the entire resource with the provided data.
   * - PATCH: Applies a partial update to the resource, allowing for specific fields to be modified.
   */
  allowedMethods: ('PUT' | 'PATCH')[]
}

/**
 * Enables removing an existing resource.
 * Endpoint: DELETE /[entity-collection-name]/{id}
 */
export interface DeleteAction extends Action {
  kind: 'delete'
  /**
   * The strategy for deletion. Default: Soft Delete.
   *
   * @default 'soft'
   */
  strategy?: 'soft' | 'hard'
  /**
   * The data retention period (in days) for soft-deleted resources.
   * This defines how long the data should be kept before it is permanently deleted.
   *
   * @default 30
   */
  retentionPeriod?: number
}

/**
 * Enables keyword-based search across specified fields.
 * Endpoint: GET /[entity-collection-name]/search
 */
export interface SearchAction extends Action {
  kind: 'search'
  /**
   * The fields within the entity to be included in the search scope.
   * Must be "indexable" and typically text-based.
   */
  fields: string[]
}

/**
 * Defines the access control policy for a specific API action.
 * Based on the predefined rule types for session-based authentication.
 */
export type AccessRule =
  | AllowPublicAccessRule
  | AllowAuthenticatedAccessRule
  | MatchResourceOwnerAccessRule
  | MatchUserRoleAccessRule
  | MatchUserPropertyAccessRule
  | MatchEmailDomainAccessRule

export interface BaseAccessRule {
  /**
   * The unique identifier for the access rule.
   * This is used to reference the rule in the API configuration.
   */
  type: string
}

/**
 * The action is allowed for all users, including unauthenticated ones.
 * This is typically used for public APIs or resources that do not require authentication.
 * It is the most permissive rule and should be used with caution.
 */
export interface AllowPublicAccessRule extends BaseAccessRule {
  type: 'public'
}
/**
 * The action is allowed for any authenticated user.
 * This rule does not impose any additional restrictions based on user properties or resource ownership.
 * It is used for resources that should be accessible to all logged-in users.
 */
export interface AllowAuthenticatedAccessRule extends BaseAccessRule {
  type: 'authenticated'
}
/**
 * The action is allowed if the authenticated user's ID matches a specific property on the resource.
 * This is typically used to restrict access to resources owned by the user.
 * For example, a user can only access their own profile or documents.
 */
export interface MatchResourceOwnerAccessRule extends BaseAccessRule {
  type: 'resourceOwner'
  /**
   * The property on the resource that should match the authenticated user's ID.
   * This is typically the ID of the user who owns the resource.
   *
   * The domain model should annotate this property with the "ResourceOwnerIdentifier" semantic
   * to indicate that it is used for ownership checks.
   */
  property: string
}

/**
 * The action is allowed if the authenticated user has a specific role.
 * This is used to enforce role-based access control (RBAC).
 * For example, only users with the "admin" role can perform certain actions.
 */
export interface MatchUserRoleAccessRule extends BaseAccessRule {
  type: 'matchUserRole'
  /**
   * The role that the authenticated user must have to access the resource.
   * This is typically a property on the user entity that defines their role.
   *
   * The domain model should annotate this property with the "UserRole" semantic
   * to indicate that it is used for role-based access control.
   */
  role: string[]
}
/**
 * The action is allowed if a specific property on the authenticated user matches an expected value.
 * This is used to enforce other user-specific restrictions.
 */
export interface MatchUserPropertyAccessRule extends BaseAccessRule {
  type: 'matchUserProperty'
  /**
   * The property on the authenticated user that should match the expected value.
   */
  property: string
  /**
   * The expected value for the user property.
   */
  value: string
}
/**
 * The action is allowed if the authenticated user's email domain matches a specific domain.
 * This is used to restrict access based on the user's email address.
 * For example, only users with an email address from "my-company.com" can access certain resources.
 */
export interface MatchEmailDomainAccessRule extends BaseAccessRule {
  type: 'matchEmailDomain'
  /**
   * The email domains that the authenticated user's email must match.
   */
  domains: string[]
}

/**
 * Defines the rate limiting and throttling policies for the entire API.
 */
export interface RateLimitingConfiguration {
  /**
   * An ordered list of rules. The first rule that matches an incoming
   * request will be applied.
   */
  rules: RateLimitRule[]
}

/**
 * Represents a single rate limiting rule that applies to a specific
 * type of client, using a token bucket algorithm.
 */
export interface RateLimitRule {
  /**
   * A human-readable description of what this rule is for.
   * e.g., "Limit anonymous users to 60 requests per hour."
   */
  description?: string

  /**
   * Defines how to group requests for rate limiting. This determines
   * who the limit applies to.
   *
   * - 'ip': Keys on the client's IP address. Best for anonymous traffic.
   * - 'userId': Keys on the authenticated user's ID. Best for logged-in users.
   * - 'role': Applies a shared limit to all users of a specific role.
   */
  key: { type: 'ip' } | { type: 'userId' } | { type: 'role'; value: string }

  /**
   * The number of requests allowed over the defined interval.
   * This is the rate at which tokens are added to the bucket.
   */
  rate: number

  /**
   * The time interval for the rate.
   */
  interval: 'second' | 'minute' | 'hour' | 'day'

  /**
   * The maximum number of requests that can be made in a burst.
   * This represents the "bucket size." A larger burst allows for
   * more requests to be made in a short period before throttling begins.
   */
  burst: number
}

export type DomainImpactKinds =
  | typeof DomainNamespaceKind
  | typeof DomainEntityKind
  | typeof DomainModelKind
  | typeof DomainPropertyKind
  | typeof DomainAssociationKind
  | typeof DataDomainKind

/**
 * The impact analysis report
 */
export interface DomainImpactReport {
  /**
   * The key of the impacted data object.
   * This is the key of the object that is being changed.
   */
  key: string
  /**
   * The kind of the impacted data object.
   * This is the kind of the object that is being changed.
   */
  kind: DomainImpactKinds
  /**
   * The list of impacted data objects.
   */
  impact: DomainImpactItem[]
  /**
   * Whether it is possible to proceed with the change.
   * If the change is not possible, the reason will be in the impact list.
   */
  canProceed: boolean
}

export interface DomainImpactItem {
  /**
   * The key of the impacted data object.
   */
  key: string
  /**
   * The kind of the impacted data object.
   */
  kind: string
  /**
   * The type of the impact.
   *
   * - `delete` - The data object would be deleted.
   */
  type: 'delete' | 'publish'
  /**
   * The impact description.
   * Explains what will happen to the impacted data object.
   * This is a human-readable description of the impact.
   * It should be clear and concise.
   */
  impact: string
  /**
   * The severity of the impact.
   *
   * - `info` - The impact is informational.
   * - `warning` - The impact can potentially cause problems but is not a blocker.
   * - `error` - The impact is a blocker and needs to be resolved before proceeding.
   */
  severity: 'info' | 'warning' | 'error'
  /**
   * The type of the relationship between two impacted objects.
   */
  relationship?: 'child'
  /**
   * The resolution of the conflict if the change will be forced.
   */
  resolution?: string
  /**
   * The optional parent of the impacted data object.
   * For example, if the impacted item is a property, this will be the entity it belongs to.
   */
  parent?: string
}

export interface DeserializeOptions {
  /**
   * The mode to use for deserialization.
   */
  mode?: DeserializationMode
  /**
   * The serialized graph to deserialize.
   * This is the JSON representation of the graph.
   */
  json?: SerializedGraph
  /**
   * The list of foreign domains that this domain depends on.
   */
  dependencies?: DataDomain[]
}

/**
 * Describes the mode for deserializing a domain graph.
 */
export type DeserializationMode = 'strict' | 'lenient'

/**
 * Describes an issue found during deserialization.
 */
export interface DeserializationIssue {
  /**
   * The type of issue encountered.
   */
  type: 'missing_node' | 'missing_edge' | 'invalid_parent' | 'missing_dependency' | 'malformed_entry' | 'unknown_kind'
  /**
   * The severity of the issue.
   */
  severity: 'error' | 'warning' | 'info'
  /**
   * A human-readable description of the issue.
   */
  message: string
  /**
   * The key of the affected node, edge, or entity if applicable.
   */
  affectedKey?: string
  /**
   * Additional context about the issue.
   */
  context?: Record<string, unknown>
  /**
   * The action taken to handle this issue in lenient mode.
   */
  resolution?: string
}

/**
 * The result of a deserialization operation.
 */
export interface DeserializationResult {
  /**
   * The deserialized graph.
   */
  graph: DataDomainGraph
  /**
   * Issues encountered during deserialization.
   */
  issues: DeserializationIssue[]
  /**
   * Whether the deserialization was successful.
   * This is set to true when a critical failures occurred.
   */
  success: boolean
}

/**
 * Available node types for search filtering.
 */
export type SearchableNodeType =
  | typeof DomainNamespaceKind
  | typeof DomainModelKind
  | typeof DomainEntityKind
  | typeof DomainPropertyKind
  | typeof DomainAssociationKind

/**
 * Search criteria for filtering domain nodes.
 */
export interface DomainSearchCriteria {
  /**
   * Text query to search for in name, displayName, and description fields.
   * Can be a string for exact match or RegExp for pattern matching.
   */
  query?: string | RegExp

  /**
   * Filter by specific node types. If not provided, all node types are included.
   */
  nodeTypes?: SearchableNodeType[]

  /**
   * Whether to include nodes from foreign domains in the search results.
   * Defaults to false.
   */
  includeForeignDomains?: boolean

  /**
   * Case-sensitive search when using string query.
   * Defaults to false (case-insensitive).
   */
  caseSensitive?: boolean
}

/**
 * A search result containing a matching domain node and metadata.
 */
export interface DomainSearchResult {
  /**
   * The matching domain node.
   */
  node: DomainGraphNodeType

  /**
   * The field(s) that matched the search query.
   */
  matchedFields: ('name' | 'displayName' | 'description')[]

  /**
   * The key used to identify this node in the graph.
   */
  key: string

  /**
   * Whether this node belongs to a foreign domain.
   */
  isForeign: boolean
}
