/**
 * MailboxAddress - Value Object for root + shard mailbox targeting
 *
 * A mailbox address uniquely identifies WHERE to deliver a message.
 * It combines a RootId (the namespace) with a ShardId (the partition).
 *
 * IMPORTANT: This is the ONLY way to construct a delivery target.
 * Do NOT use string concatenation or heuristics to derive mailbox addresses.
 */

import { RootId } from './root_id';
import { ShardId, DEFAULT_SHARD } from './shard_id';

export class MailboxAddress {
  private constructor(
    private readonly _root: RootId,
    private readonly _shard: ShardId
  ) {}

  /**
   * Create a mailbox address for a specific root and shard.
   */
  static of(root: RootId, shard?: ShardId): MailboxAddress {
    return new MailboxAddress(root, shard ?? ShardId.default());
  }

  /**
   * Create a mailbox address from string values.
   * Uses default shard if not specified.
   */
  static fromStrings(root: string, shard?: string): MailboxAddress {
    return new MailboxAddress(
      RootId.of(root),
      shard ? ShardId.of(shard) : ShardId.default()
    );
  }

  /**
   * Create a mailbox address with the default shard (for browser tabs).
   */
  static defaultShard(root: RootId): MailboxAddress {
    return new MailboxAddress(root, ShardId.default());
  }

  /**
   * Get the root.
   */
  get root(): RootId {
    return this._root;
  }

  /**
   * @deprecated Use .root instead.
   */
  get realm(): RootId {
    return this._root;
  }

  /**
   * Get the shard.
   */
  get shard(): ShardId {
    return this._shard;
  }

  /**
   * Get the root as a string (convenience).
   */
  get rootString(): string {
    return this._root.value;
  }

  /**
   * @deprecated Use .rootString instead.
   */
  get realmString(): string {
    return this._root.value;
  }

  /**
   * Get the shard as a string (convenience).
   */
  get shardString(): string {
    return this._shard.value;
  }

  /**
   * Check equality.
   */
  equals(other: MailboxAddress | null | undefined): boolean {
    if (!other) return false;
    return this._root.equals(other._root) && this._shard.equals(other._shard);
  }

  /**
   * Unique key for Map/Set usage.
   */
  toKey(): string {
    return `${this._root.value}:${this._shard.value}`;
  }

  toString(): string {
    return `MailboxAddress(${this._root.value}, ${this._shard.value})`;
  }

  toJSON(): { root: string; shard: string } {
    return {
      root: this._root.value,
      shard: this._shard.value,
    };
  }
}

export function isMailboxAddress(value: unknown): value is MailboxAddress {
  return value instanceof MailboxAddress;
}
