import type {
  VoiceProvider,
  VoiceProviderConnectInput,
  VoiceProviderSession,
} from "./types.ts";
import type { WebSocketFactory } from "./realtime-websocket.ts";
import { OpenAiRealtimeProvider, parseOpenAiRealtimeMessage } from "./openai-realtime.ts";

export interface XaiGrokVoiceProviderOptions {
  apiKey: string;
  model: string;
  realtimeUrl?: string;
  defaultVoice?: string;
  phiAllowed: boolean;
  webSocketFactory?: WebSocketFactory;
}

export class XaiGrokVoiceProvider implements VoiceProvider {
  readonly kind = "grok_voice" as const;

  constructor(private readonly opts: XaiGrokVoiceProviderOptions) {}

  async connect(input: VoiceProviderConnectInput): Promise<VoiceProviderSession> {
    if (!this.opts.phiAllowed) {
      throw new Error("Grok Voice is not enabled for PHI. Set XAI_PHI_ALLOWED=1 after compliance approval.");
    }

    // xAI documents OpenAI Realtime compatibility for the voice endpoint, so
    // share the wire adapter while pinning xAI's URL, model, and voice.
    const provider = new OpenAiRealtimeProvider({
      apiKey: this.opts.apiKey,
      model: this.opts.model,
      realtimeUrl: this.opts.realtimeUrl ?? "wss://api.x.ai/v1/realtime",
      defaultVoice: this.opts.defaultVoice ?? "eve",
      sessionShape: "legacy",
      webSocketFactory: this.opts.webSocketFactory,
    });

    const session = await provider.connect({
      ...input,
      voice: input.voice ?? this.opts.defaultVoice ?? "eve",
    });

    return {
      provider: this.kind,
      sessionId: session.sessionId,
      sendAudio: (frame) => session.sendAudio(frame),
      sendText: (text) => session.sendText(text),
      sendToolResult: (toolCallId, result) => session.sendToolResult(toolCallId, result),
      interrupt: () => session.interrupt(),
      close: (reason) => session.close(reason),
    };
  }
}

export { parseOpenAiRealtimeMessage as parseXaiGrokVoiceMessage };
