import { mxesc1Decode, mxesc1Encode } from './mxesc1';

export type WireProfileName = 'matrix3' | 'mxenv1';

export interface IngressAddress {
  profile: WireProfileName;
  root: string;
  /** @deprecated Use root instead */
  realm?: string;
  shard?: string; // mxenv1
}

function assertRootSegment(root: string): void {
  if (!root || typeof root !== 'string') throw new Error('root must be a non-empty string');
  if (root.includes('/')) throw new Error(`root must not contain slashes: ${root}`);
  if (root.includes('+') || root.includes('#')) throw new Error('root must not contain wildcards');
  // DNS roots may contain dots (e.g., 'com.nimbletec.richard.santomauro')
}

/** Legacy Matrix-3 mailbox: public.ingress.<mxesc1(root)> */
export function getLegacyIngressTopic(root: string): string {
  // legacy format uses mxesc1 because the root may include characters unsafe in a dot-segment.
  return `public.ingress.${mxesc1Encode(root)}`;
}

export function extractLegacyRootFromIngressTopic(topic: string): string | null {
  const prefix = 'public.ingress.';
  if (!topic.startsWith(prefix)) return null;
  try {
    return mxesc1Decode(topic.slice(prefix.length));
  } catch {
    return null;
  }
}

/** @deprecated Use extractLegacyRootFromIngressTopic instead */
export const extractLegacyRealmFromIngressTopic = extractLegacyRootFromIngressTopic;

/** DNS-hierarchical ingress topic: {root}.$ingress.{shard} */
export function getMxIngressTopic(root: string, shard: string = '00'): string {
  assertRootSegment(root);
  if (!/^[0-9]{2}$/.test(shard)) throw new Error(`invalid shard '${shard}' (expected two digits like '00')`);
  return `${root}.$ingress.${shard}`;
}

export function extractMxIngressFromTopic(topic: string): { root: string; shard: string } | null {
  // Format: {root}.$ingress.{shard} — find the .$ingress. separator
  const ingressIdx = topic.indexOf('.$ingress.');
  if (ingressIdx < 0) return null;
  const root = topic.slice(0, ingressIdx);
  const shard = topic.slice(ingressIdx + '.$ingress.'.length);
  if (!/^[0-9]{2}$/.test(shard)) return null;
  if (!root) return null;
  return { root, shard };
}

/**
 * Internal semantic topic — returns the semantic path directly.
 * With DNS hierarchical addressing, the transport (NatsTransport) handles
 * root prefix encoding. The federation layer just passes semantic topics.
 */
export function getInternalTopic(_root: string, toPath: string): string {
  if (!toPath || typeof toPath !== 'string') throw new Error('toPath must be a non-empty string');
  if (toPath.startsWith('/')) throw new Error('toPath must not start with /');
  return toPath;
}
