/**
 * Wire Codec
 *
 * Converts between semantic Matrix URIs and wire topics.
 * With DNS hierarchical addressing, wire topics are dot-separated
 * and the transport handles root prefix encoding.
 *
 * @module federation/wire_codec
 */

import { parseMatrixUri, type Plane } from './uri';

/**
 * Parameters for MXTOPIC-2 wire topic encoding/decoding.
 */
export interface WireTopicParams {
  /** Globally unique root identity (e.g., 'matrix-3', 'flowpad-tab-xyz') */
  root: string;
  /** @deprecated Use root instead */
  realm?: string;
  /** Filesystem-like placement hierarchy segments */
  mountSegments: string[];
  /** Dot-delimited supervision topology (e.g., 'app.editor.sidebar') */
  componentPath: string;
  /** Message direction */
  plane: 'accepts' | 'emits';
  /** Message name */
  messageName: string;
}

/**
 * Encode semantic coordinates to wire topic.
 *
 * With DNS hierarchical addressing, the wire topic is built from
 * mount segments + component path + plane + message name, dot-separated.
 * The transport layer handles root prefix.
 *
 * @example
 * encodeToWireTopic({
 *   root: 'com.example',
 *   mountSegments: ['root', 'project'],
 *   componentPath: 'tree',
 *   plane: 'accepts',
 *   messageName: 'introspect'
 * });
 * // => 'root.project.tree.accepts.introspect'
 */
export function encodeToWireTopic(params: WireTopicParams): string {
  const {
    mountSegments,
    componentPath,
    plane,
    messageName
  } = params;

  // Validate plane
  if (plane !== 'accepts' && plane !== 'emits') {
    throw new Error(`Invalid plane: ${plane}. Must be 'accepts' or 'emits'`);
  }

  // Build semantic topic: mount.component.plane.message
  const parts = [
    ...mountSegments,
    `${componentPath}.${plane}.${messageName}`
  ];

  return parts.join('.');
}

/**
 * Decode a wire topic to semantic coordinates.
 *
 * With DNS hierarchical addressing, wire topics are dot-separated.
 * The root is not embedded in the topic -- it's a transport concern.
 *
 * @returns Parsed params or null if invalid format
 */
export function decodeFromWireTopic(wireTopic: string): WireTopicParams | null {
  // Find .accepts. or .emits. pattern to split the topic
  const acceptsIdx = wireTopic.lastIndexOf('.accepts.');
  const emitsIdx = wireTopic.lastIndexOf('.emits.');

  const planeIdx = Math.max(acceptsIdx, emitsIdx);
  if (planeIdx === -1) {
    return null;
  }

  const plane: 'accepts' | 'emits' = acceptsIdx > emitsIdx ? 'accepts' : 'emits';
  const beforePlane = wireTopic.slice(0, planeIdx);
  const messageName = wireTopic.slice(planeIdx + (plane === 'accepts' ? '.accepts.'.length : '.emits.'.length));

  if (!beforePlane || !messageName) {
    return null;
  }

  // Split beforePlane into mount segments + component path
  // The last dot-segment before .accepts./.emits. is the component path
  const segments = beforePlane.split('.');
  const componentPath = segments.pop() ?? '';
  if (!componentPath) return null;

  return {
    root: '', // Root is a transport concern, not embedded in topic
    realm: '', // Deprecated alias
    mountSegments: segments,
    componentPath,
    plane,
    messageName
  };
}

/**
 * Legacy return type for parseSemanticTopic (compatibility).
 * @deprecated Use parseMatrixUri which returns MatrixUri instead.
 */
export interface SemanticTopicParams {
  scheme: 'matrix';
  root?: string;
  /** @deprecated Use root instead */
  realm?: string;
  mount: string;
  componentPath: string;
  plane: 'accepts' | 'emits';
  messageName: string;
  /** @deprecated Merged into root */
  principal?: string;
}

/**
 * Parse a semantic Matrix URI to coordinates.
 *
 * @deprecated Use parseMatrixUri() directly. This is a compatibility wrapper.
 *
 * @example
 * parseSemanticTopic('matrix-3/daemon/project/tree.accepts.introspect')
 * // => { scheme: 'matrix', root: 'matrix-3', mount: 'daemon/project', componentPath: 'tree', plane: 'accepts', messageName: 'introspect' }
 */
export function parseSemanticTopic(uri: string): SemanticTopicParams | null {
  const parsed = parseMatrixUri(uri);
  if (!parsed) return null;

  return {
    scheme: 'matrix',
    principal: parsed.principal,
    root: parsed.root,
    realm: parsed.root,
    mount: parsed.mountSegments.join('/'),
    componentPath: parsed.componentPath,
    plane: parsed.plane,
    messageName: parsed.messageName,
  };
}
