import type { Context } from "@wrnexus/core";
import { exportSubjectContext, importSubjectContext, type SubjectContext } from "@wrnexus/rpc";
import type { PubSub } from "./index.ts";

const PUBSUB_AUDIENCE = "wrnexus-pubsub";

interface SubjectEnvelope<T> {
  payload: T;
  identity?: string;
}

export interface SubjectPubSub {
  publish<T>(ctx: Context, topic: string, message: T): Promise<void>;
  subscribe<T>(
    pattern: string,
    handler: (message: T, topic: string, subject?: SubjectContext) => void | Promise<void>,
  ): () => void;
}

/**
 * Authenticated pub/sub envelope. The token uses a fixed, purpose-specific
 * audience; subscribers verify it before exposing the message to a handler.
 */
export function subjectPubSub(bus: PubSub): SubjectPubSub {
  return {
    async publish(ctx, topic, message) {
      const identity = await exportSubjectContext(ctx, PUBSUB_AUDIENCE);
      await bus.publish<SubjectEnvelope<typeof message>>(topic, {
        payload: message,
        ...(identity ? { identity } : {}),
      });
    },
    subscribe(pattern, handler) {
      return bus.subscribe<SubjectEnvelope<unknown>>(pattern, async (envelope, topic) => {
        if (!envelope || typeof envelope !== "object" || !("payload" in envelope)) return;
        let subject: SubjectContext | undefined;
        if (envelope.identity !== undefined) {
          if (typeof envelope.identity !== "string") return;
          try {
            subject = await importSubjectContext(envelope.identity, PUBSUB_AUDIENCE);
          } catch {
            return; // Never downgrade a malformed claimed identity to anonymous.
          }
        }
        await handler(envelope.payload as never, topic, subject);
      });
    },
  };
}
