import type { DataDomain } from './DataDomain.js'

export interface DomainElementSchema {
  /**
   * The kind of the domain element.
   */
  kind: string
  /**
   * The unique key of the domain element.
   */
  key: string
}

export abstract class DomainElement implements DomainElementSchema {
  /**
   * A reference to the root DataDomain instance.
   */
  protected root: DataDomain

  /**
   * The root DataDomain instance.
   */
  get domain(): DataDomain {
    return this.root
  }

  abstract accessor kind: string

  /**
   * The unique key of the domain element.
   * Since keys are immutable, we use a private field to store the key.
   */
  #key: string

  /**
   * The unique key of the domain element.
   */
  get key(): string {
    return this.#key
  }

  #namespace: string

  /**
   * The key of the DataDomain this element belongs to.
   * In a data domain that has foreign namespaces, this is the key of the namespace this element originally belongs to.
   *
   * It might be different from the `domain.key` if the element is a foreign object.
   */
  get namespace(): string {
    return this.#namespace
  }

  /**
   * @param root The root DataDomain instance.
   * @param key The unique key of the domain element.
   */
  constructor(root: DataDomain, key: string) {
    this.root = root
    this.#key = key
    // When dependencies are loaded, they all first belong to the root domain.
    // When the foreign domain is merged, the object is transferred to the other domain,
    // but the namespace is still the root domain key.
    this.#namespace = root.key
  }
}
