import type { z } from "zod";
import type { RealtimeRegistryProtocol } from "@repo/core-shared/di/bind-protocols";
import type { RealtimeChannelDescriptor } from "./realtime-channel";
import type { IInboundDescriptor } from "./realtime-handler.interface";

export interface IRealtimeHandlerRegistry extends RealtimeRegistryProtocol {
  register<T>(entry: IInboundDescriptor<string, z.ZodType<T>>): void;
  getInboundDescriptor(channelName: string): IInboundDescriptor<string, z.ZodType> | null;
  list(): IInboundDescriptor<string, z.ZodType>[];
  /** Register an outbound-only channel so Gate 2 can authorize subscriptions to it. */
  registerChannel(descriptor: RealtimeChannelDescriptor<string, z.ZodType>): void;
  listChannels(): RealtimeChannelDescriptor<string, z.ZodType>[];
}

export class RealtimeHandlerRegistry implements IRealtimeHandlerRegistry {
  private readonly entries = new Map<string, IInboundDescriptor<string, z.ZodType>>();
  private readonly channels = new Map<string, RealtimeChannelDescriptor<string, z.ZodType>>();

  register<T>(entry: IInboundDescriptor<string, z.ZodType<T>>): void {
    this.entries.set(entry.descriptor.name, entry as IInboundDescriptor<string, z.ZodType>);
    // Also add the descriptor to the channel map so Gate 2 can authorize subscriptions.
    this.channels.set(entry.descriptor.name, entry.descriptor);
  }

  getInboundDescriptor(channelName: string): IInboundDescriptor<string, z.ZodType> | null {
    return this.entries.get(channelName) ?? null;
  }

  list(): IInboundDescriptor<string, z.ZodType>[] {
    return Array.from(this.entries.values());
  }

  registerChannel(descriptor: RealtimeChannelDescriptor<string, z.ZodType>): void {
    this.channels.set(descriptor.name, descriptor);
  }

  listChannels(): RealtimeChannelDescriptor<string, z.ZodType>[] {
    return Array.from(this.channels.values());
  }
}
