/**
 * # Macroforge Traits Module
 *
 * This module defines TypeScript interfaces that correspond to Rust-like traits.
 * These interfaces describe the shape of the methods generated by Macroforge's
 * derive macros for interfaces, enums, and type aliases.
 *
 * For **classes**, the generated methods are instance methods (e.g., `user.clone()`).
 * For **interfaces/enums/type aliases**, the generated methods are namespace
 * functions that take the value as the first parameter (e.g., `User.clone(user)`).
 *
 * ## Usage
 *
 * These traits are primarily used for type checking generated code:
 *
 * ```typescript
 * import type { Clone, Debug } from "macroforge/traits";
 *
 * // Type-check that a namespace implements Clone
 * const UserNs: Clone<User> = User;
 * ```
 *
 * @module macroforge/traits
 */

/**
 * Trait for types that can be deep-copied.
 *
 * Analogous to Rust's `Clone` trait. The generated `clone` method creates
 * an independent copy of the value.
 *
 * @template T - The type being cloned
 *
 * @example
 * ```typescript
 * // For interfaces/type aliases, use as namespace:
 * const cloned = UserNs.clone(original);
 *
 * // For classes, methods are on the instance:
 * const cloned = original.clone();
 * ```
 */
export interface Clone<T> {
  /**
   * Creates a deep copy of the value.
   * @param self - The value to clone
   * @returns A new independent copy of the value
   */
  readonly clone: (self: T) => T;
}

/**
 * Trait for types with a human-readable string representation.
 *
 * Analogous to Rust's `Debug` trait. The generated `toString` method
 * produces a string like `"TypeName { field1: value1, field2: value2 }"`.
 *
 * @template T - The type being formatted
 *
 * @example
 * ```typescript
 * console.log(User.toString(user));
 * // Output: "User { id: 1, name: Alice }"
 * ```
 */
export interface Debug<T> {
  /**
   * Returns a debug string representation of the value.
   * @param self - The value to format
   * @returns A human-readable string for debugging
   */
  readonly toString: (self: T) => string;
}

/**
 * Trait for types with a default value.
 *
 * Analogous to Rust's `Default` trait. The generated `defaultValue` method
 * creates an instance with all fields set to their default values.
 *
 * @template T - The type being constructed
 *
 * @example
 * ```typescript
 * const user = User.defaultValue();
 * // Creates: { id: 0, name: "", active: false }
 * ```
 */
export interface Default<T> {
  /**
   * Creates a new instance with default values for all fields.
   * @returns A new instance with default field values
   */
  readonly defaultValue: () => T;
}

/**
 * Trait for types that support equality comparison.
 *
 * Analogous to Rust's `PartialEq` trait. The generated `equals` method
 * performs structural equality comparison on all non-skipped fields.
 *
 * @template T - The type being compared
 *
 * @example
 * ```typescript
 * if (User.equals(user1, user2)) {
 *   console.log("Users are equal");
 * }
 * ```
 */
export interface PartialEq<T> {
  /**
   * Compares two values for equality.
   * @param self - The first value
   * @param other - The second value (accepts unknown for flexibility)
   * @returns `true` if the values are equal, `false` otherwise
   */
  readonly equals: (self: T, other: unknown) => boolean;
}

/**
 * Trait for types that can produce a hash code.
 *
 * Analogous to Rust's `Hash` trait. The generated `hashCode` method
 * computes a 32-bit integer hash suitable for use in hash-based collections.
 *
 * **Hash Contract**: Objects that are equal (via `PartialEq`) must produce
 * the same hash code.
 *
 * @template T - The type being hashed
 *
 * @example
 * ```typescript
 * const hash = User.hashCode(user);
 * // Use in Map: map.set(hash, user);
 * ```
 */
export interface Hash<T> {
  /**
   * Computes a hash code for the value.
   * @param self - The value to hash
   * @returns A 32-bit integer hash code
   */
  readonly hashCode: (self: T) => number;
}

/**
 * Trait for types with partial ordering.
 *
 * Analogous to Rust's `PartialOrd` trait. The generated `compareTo` method
 * returns a number for comparable values, or `null` for incomparable values.
 *
 * @template T - The type being compared
 *
 * @example
 * ```typescript
 * const cmp = User.compareTo(user1, user2);
 * if (cmp !== null) {
 *   if (cmp < 0) console.log("user1 < user2");
 *   else if (cmp > 0) console.log("user1 > user2");
 *   else console.log("user1 == user2");
 * } else {
 *   console.log("Incomparable");
 * }
 * ```
 */
export interface PartialOrd<T> {
  /**
   * Compares two values for ordering.
   * @param self - The first value
   * @param other - The second value
   * @returns `-1` if self < other, `0` if equal, `1` if self > other, or `null` if incomparable
   */
  readonly compareTo: (self: T, other: unknown) => number | null;
}

/**
 * Trait for types with total ordering.
 *
 * Analogous to Rust's `Ord` trait. The generated `compareTo` method
 * always returns a number (never null) - all values are comparable.
 *
 * @template T - The type being compared
 *
 * @example
 * ```typescript
 * // Sort an array using Ord
 * users.sort((a, b) => User.compareTo(a, b));
 * ```
 */
export interface Ord<T> {
  /**
   * Compares two values for ordering (total order).
   * @param self - The first value
   * @param other - The second value
   * @returns `-1` if self < other, `0` if equal, `1` if self > other
   */
  readonly compareTo: (self: T, other: T) => number;
}

/**
 * Trait for types that can be serialized to JSON.
 *
 * Analogous to Rust's serde `Serialize` trait. The generated methods
 * convert objects to JSON with cycle detection via `__id`/`__ref` markers.
 *
 * @template T - The type being serialized
 *
 * @example
 * ```typescript
 * const json = User.toStringifiedJSON(user);
 * // => '{"__type":"User","__id":1,"name":"Alice"}'
 *
 * const obj = User.toObject(user);
 * // => { __type: "User", __id: 1, name: "Alice" }
 * ```
 */
export interface Serialize<T> {
  /**
   * Serializes the value to a JSON string.
   * @param self - The value to serialize
   * @returns JSON string with `__type` and `__id` markers
   */
  readonly toStringifiedJSON: (self: T) => string;

  /**
   * Converts the value to a plain JavaScript object.
   * @param self - The value to convert
   * @returns Plain object suitable for JSON.stringify
   */
  readonly toObject: (self: T) => Record<string, unknown>;
}

/**
 * Trait for types that can be deserialized from JSON.
 *
 * Analogous to Rust's serde `Deserialize` trait. The generated methods
 * parse JSON, resolve `__ref` markers, and validate field values.
 *
 * @template T - The type being deserialized
 *
 * @example
 * ```typescript
 * import { Result } from "macroforge/utils";
 *
 * const result = User.fromStringifiedJSON(json);
 * if (Result.isOk(result)) {
 *   const user = result.value;
 * } else {
 *   console.error(result.error); // Validation errors
 * }
 * ```
 */
export interface Deserialize<T> {
  /**
   * Deserializes a value from a JSON string.
   * @param json - JSON string to parse
   * @returns The deserialized value (may throw on invalid input)
   */
  readonly fromStringifiedJSON: (json: string) => T;

  /**
   * Deserializes a value from a plain JavaScript object.
   * @param obj - Object to deserialize from
   * @returns The deserialized value (may throw on invalid input)
   */
  readonly fromObject: (obj: unknown) => T;
}
