// src/engine/core/Ports.ts

import { TopicRouter } from '../messaging/TopicRouter';
import type { MxEnvelope } from '../messaging/MxEnvelope';
import type { IMatrixContext } from './IMatrixContext';
import type { TransportHandler } from '../remoting/ITransportAdapter';

/**
 * One‑shot send to a child mount's $inbox.
 */
export function sendTo(
  context: IMatrixContext,
  childMount: string,
  command: string,
  payload?: unknown
): void {
  context.transport.publish(TopicRouter.inbox(childMount), {
    op: command,
    payload: payload ?? {},
  } as MxEnvelope);
}

/**
 * "Parent view" onto a child: send commands and listen to its events.
 */
export function parentToChild(context: IMatrixContext, childMount: string) {
  const transport = context.transport;
  return {
    send(command: string, payload?: unknown) {
      transport.publish(TopicRouter.inbox(childMount), {
        op: command,
        payload: payload ?? {},
      } as MxEnvelope);
    },
    on(event: string, handler: TransportHandler) {
      const eventsTopic = TopicRouter.events(childMount);
      return transport.subscribe(eventsTopic, (payload, meta) => {
        const envelope = payload as MxEnvelope;
        if (envelope?.op === event) handler(envelope.payload, meta);
      });
    }
  };
}

/**
 * "Child view" onto itself: handle commands and emit events at its own mount.
 */
export function childPorts(context: IMatrixContext) {
  const mount = context.mount;
  const transport = context.transport;

  return {
    onCommand(command: string, handler: TransportHandler) {
      const inboxTopic = TopicRouter.inbox(mount);
      return transport.subscribe(inboxTopic, (payload, meta) => {
        const envelope = payload as MxEnvelope;
        if (envelope?.op === command) handler(envelope.payload, meta);
      });
    },
    emitEvent(event: string, payload?: unknown) {
      transport.publish(TopicRouter.events(mount), {
        op: event,
        payload: payload ?? {},
        from: mount,
      } as MxEnvelope);
    }
  };
}

export const Ports = { sendTo, parentToChild, childPorts };
