/**
 * @fileoverview Base value object class for domain-driven design
 *
 * This module provides the base class for all value objects in the domain layer.
 * Value objects are immutable objects that are defined by their attributes rather
 * than a unique identity. They provide type safety and encapsulation of business rules.
 */

/**
 * Base class for all value objects in the domain
 *
 * Value objects are immutable and compared by their properties rather than identity.
 * They encapsulate validation logic and provide type safety for domain concepts.
 *
 * @example
 * ```typescript
 * class Money extends ValueObject<{ amount: number; currency: string }> {
 *   constructor(amount: number, currency: string) {
 *     if (amount < 0) throw new Error('Amount cannot be negative');
 *     super({ amount, currency });
 *   }
 *
 *   get amount(): number {
 *     return this.props.amount;
 *   }
 *
 *   get currency(): string {
 *     return this.props.currency;
 *   }
 * }
 * ```
 */
export abstract class ValueObject<T> {
  protected readonly props: T;

  protected constructor(props: T) {
    this.props = Object.freeze(props);
  }

  /**
   * Checks equality between two value objects
   *
   * Two value objects are equal if all their properties are equal.
   * This method performs deep equality checking for nested objects.
   *
   * @param other - The value object to compare with
   * @returns True if the value objects are equal, false otherwise
   */
  public equals(other: ValueObject<T>): boolean {
    if (other === null || other === undefined) {
      return false;
    }

    if (other.props === undefined) {
      return false;
    }

    return JSON.stringify(this.props) === JSON.stringify(other.props);
  }

  /**
   * Creates a copy of the value object with updated properties
   *
   * Since value objects are immutable, this method creates a new instance
   * with the specified properties updated.
   *
   * @param props - Partial properties to update
   * @returns A new instance of the value object with updated properties
   */
  protected copyWith(_props: Partial<T>): this {
    // Using unknown type and runtime validation for constructor to enable proper inheritance
    const ctor = this.constructor as new (_props: T) => this;
    return new ctor({ ...this.props, ..._props });
  }
}
