import type { ChatMessage, ResponseProvider } from './runtime';
import { GoogleGenAI, Modality, type LiveServerMessage } from '@google/genai';

type GeminiLiveOptions = {
  apiKey?: string;
  model?: string;
  systemPrompt?: string;
};

export class GeminiLiveProvider implements ResponseProvider {
  private readonly apiKey?: string;
  private readonly model: string;
  private readonly systemPrompt: string;
  private client?: GoogleGenAI;

  constructor(options: GeminiLiveOptions = {}) {
    this.apiKey = options.apiKey ?? process.env.GEMINI_API_KEY;
    this.model = options.model ?? 'gemini-2.0-flash-live-001';
    this.systemPrompt = options.systemPrompt ?? 'You are a concise, friendly streaming VTuber agent replying to live chat.';
  }

  async generateReply(message: ChatMessage): Promise<string> {
    if (!this.apiKey) {
      throw new Error('GEMINI_API_KEY is not set.');
    }

    this.client ??= new GoogleGenAI({ apiKey: this.apiKey });

    const textChunks: string[] = [];
    const queue: LiveServerMessage[] = [];

    const session = await this.client.live.connect({
      model: this.model.startsWith('models/') ? this.model : `models/${this.model}`,
      config: {
        responseModalities: [Modality.TEXT],
        systemInstruction: this.systemPrompt,
      },
      callbacks: {
        onmessage: (msg) => {
          queue.push(msg);

          const anyMsg = msg as any;
          const serverContent = anyMsg.serverContent;
          const directText = anyMsg.text;
          if (typeof directText === 'string' && directText.trim()) {
            textChunks.push(directText);
          }

          const modelTurn = serverContent?.modelTurn;
          const parts = modelTurn?.parts ?? [];
          for (const part of parts) {
            if (typeof part?.text === 'string' && part.text.trim()) {
              textChunks.push(part.text);
            }
          }

          const outputTranscription = serverContent?.outputTranscription?.text;
          if (typeof outputTranscription === 'string' && outputTranscription.trim()) {
            textChunks.push(outputTranscription);
          }
        },
        onerror: (e) => {
          throw e;
        },
      },
    });

    try {
      await session.sendClientContent({
        turns: `${message.author}: ${message.text}`,
      } as any);

      const started = Date.now();
      while (Date.now() - started < 15000) {
        const done = queue.find((msg: any) => msg.serverContent?.turnComplete);
        if (done) break;
        await new Promise((resolve) => setTimeout(resolve, 50));
      }

      const reply = textChunks.join(' ').replace(/\s+/g, ' ').trim();
      if (!reply) {
        return `[gemini-live empty:${this.model}] ${message.author}: ${message.text}`;
      }
      return reply;
    } finally {
      session.close();
    }
  }

  describeSession() {
    return {
      model: this.model,
      systemPrompt: this.systemPrompt,
      transport: 'to-be-implemented'
    };
  }
}
