
import React, { useEffect, useRef, useState } from 'react';
import { GoogleGenAI, LiveServerMessage, Modality, Blob } from '@google/genai';
import { Language, translations } from '../i18n';

interface LiveAssistantProps {
  language: Language;
  onClose: () => void;
}

const LiveAssistant: React.FC<LiveAssistantProps> = ({ language, onClose }) => {
  const [status, setStatus] = useState<'connecting' | 'listening' | 'speaking' | 'error'>('connecting');
  const [transcript, setTranscript] = useState('');
  const [modelResponse, setModelResponse] = useState('');
  
  const audioContextRef = useRef<AudioContext | null>(null);
  const outputAudioContextRef = useRef<AudioContext | null>(null);
  const nextStartTimeRef = useRef(0);
  const sourcesRef = useRef<Set<AudioBufferSourceNode>>(new Set());
  const sessionRef = useRef<any>(null);

  const t = translations[language].assistant;

  const decode = (base64: string) => {
    const binaryString = atob(base64);
    const bytes = new Uint8Array(binaryString.length);
    for (let i = 0; i < binaryString.length; i++) {
      bytes[i] = binaryString.charCodeAt(i);
    }
    return bytes;
  };

  const decodeAudioData = async (data: Uint8Array, ctx: AudioContext, sampleRate: number, numChannels: number) => {
    const dataInt16 = new Int16Array(data.buffer);
    const frameCount = dataInt16.length / numChannels;
    const buffer = ctx.createBuffer(numChannels, frameCount, sampleRate);
    for (let channel = 0; channel < numChannels; channel++) {
      const channelData = buffer.getChannelData(channel);
      for (let i = 0; i < frameCount; i++) {
        channelData[i] = dataInt16[i * numChannels + channel] / 32768.0;
      }
    }
    return buffer;
  };

  const encode = (bytes: Uint8Array) => {
    let binary = '';
    for (let i = 0; i < bytes.byteLength; i++) {
      binary += String.fromCharCode(bytes[i]);
    }
    return btoa(binary);
  };

  const createBlob = (data: Float32Array): Blob => {
    const int16 = new Int16Array(data.length);
    for (let i = 0; i < data.length; i++) {
      int16[i] = data[i] * 32768;
    }
    return {
      data: encode(new Uint8Array(int16.buffer)),
      mimeType: 'audio/pcm;rate=16000',
    };
  };

  useEffect(() => {
    const startSession = async () => {
      try {
        const ai = new GoogleGenAI({ apiKey: process.env.API_KEY });
        const inputCtx = new (window.AudioContext || (window as any).webkitAudioContext)({ sampleRate: 16000 });
        const outputCtx = new (window.AudioContext || (window as any).webkitAudioContext)({ sampleRate: 24000 });
        audioContextRef.current = inputCtx;
        outputAudioContextRef.current = outputCtx;

        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        
        const sessionPromise = ai.live.connect({
          model: 'gemini-2.5-flash-native-audio-preview-12-2025',
          callbacks: {
            onopen: () => {
              setStatus('listening');
              const source = inputCtx.createMediaStreamSource(stream);
              const scriptProcessor = inputCtx.createScriptProcessor(4096, 1, 1);
              scriptProcessor.onaudioprocess = (e) => {
                const inputData = e.inputBuffer.getChannelData(0);
                const pcmBlob = createBlob(inputData);
                sessionPromise.then(s => s.sendRealtimeInput({ media: pcmBlob }));
              };
              source.connect(scriptProcessor);
              scriptProcessor.connect(inputCtx.destination);
            },
            onmessage: async (message: LiveServerMessage) => {
              if (message.serverContent?.inputTranscription) {
                setTranscript(prev => prev + message.serverContent!.inputTranscription!.text);
              }
              if (message.serverContent?.outputTranscription) {
                setModelResponse(prev => prev + message.serverContent!.outputTranscription!.text);
              }

              const audioBase64 = message.serverContent?.modelTurn?.parts[0]?.inlineData?.data;
              if (audioBase64) {
                setStatus('speaking');
                nextStartTimeRef.current = Math.max(nextStartTimeRef.current, outputCtx.currentTime);
                const buffer = await decodeAudioData(decode(audioBase64), outputCtx, 24000, 1);
                const source = outputCtx.createBufferSource();
                source.buffer = buffer;
                source.connect(outputCtx.destination);
                source.addEventListener('ended', () => {
                  sourcesRef.current.delete(source);
                  if (sourcesRef.current.size === 0) setStatus('listening');
                });
                source.start(nextStartTimeRef.current);
                nextStartTimeRef.current += buffer.duration;
                sourcesRef.current.add(source);
              }

              if (message.serverContent?.interrupted) {
                sourcesRef.current.forEach(s => s.stop());
                sourcesRef.current.clear();
                nextStartTimeRef.current = 0;
                setStatus('listening');
              }

              if (message.serverContent?.turnComplete) {
                setTranscript('');
                setModelResponse('');
              }
            },
            onerror: () => setStatus('error'),
            onclose: () => setStatus('error'),
          },
          config: {
            responseModalities: [Modality.AUDIO],
            speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName: 'Zephyr' } } },
            systemInstruction: t.systemInstruction,
            inputAudioTranscription: {},
            outputAudioTranscription: {},
          }
        });

        sessionRef.current = await sessionPromise;
      } catch (e) {
        console.error(e);
        setStatus('error');
      }
    };

    startSession();

    return () => {
      if (sessionRef.current) sessionRef.current.close();
      if (audioContextRef.current) audioContextRef.current.close();
      if (outputAudioContextRef.current) outputAudioContextRef.current.close();
    };
  }, [language]);

  return (
    <div className="fixed inset-0 z-[100] flex flex-col items-center justify-end bg-black/40 backdrop-blur-sm p-4 animate-in fade-in slide-in-from-bottom-10">
      <div className="w-full max-w-lg bg-white dark:bg-slate-900 rounded-3xl shadow-2xl overflow-hidden mb-safe">
        <div className="p-6 flex flex-col items-center text-center">
          <div className="w-full flex justify-between items-center mb-6">
            <span className="text-xs font-bold text-primary uppercase tracking-widest">{t.title}</span>
            <button onClick={onClose} className="text-slate-400 hover:text-slate-600">
              <span className="material-icons">close</span>
            </button>
          </div>

          <div className="relative mb-8">
            <div className={`w-24 h-24 rounded-full flex items-center justify-center transition-all duration-500 ${
              status === 'connecting' ? 'bg-slate-100' :
              status === 'listening' ? 'bg-primary/20 animate-pulse' :
              status === 'speaking' ? 'bg-purple-500/20 scale-110' : 'bg-red-500/20'
            }`}>
              <span className={`material-icons text-4xl ${
                status === 'listening' ? 'text-primary' : 
                status === 'speaking' ? 'text-purple-600' : 'text-slate-400'
              }`}>
                {status === 'listening' ? 'mic' : status === 'speaking' ? 'graphic_eq' : 'settings_voice'}
              </span>
            </div>
          </div>

          <h2 className="text-lg font-bold mb-2">
            {status === 'connecting' ? t.connecting :
             status === 'listening' ? t.listening :
             status === 'speaking' ? t.speaking : t.error}
          </h2>

          <div className="w-full h-24 bg-slate-50 dark:bg-slate-800 rounded-2xl p-4 overflow-y-auto mb-6 text-sm italic text-slate-600 dark:text-slate-400">
            {transcript && <p className="mb-2">" {transcript} "</p>}
            {modelResponse && <p className="text-primary font-medium">Assistant: {modelResponse}</p>}
            {!transcript && !modelResponse && status === 'listening' && (
              <p className="opacity-50">{t.placeholder}</p>
            )}
          </div>

          <button 
            onClick={onClose}
            className="w-full py-3.5 bg-slate-100 dark:bg-slate-800 text-slate-700 dark:text-slate-300 rounded-xl font-bold transition-colors active:bg-slate-200"
          >
            {t.close}
          </button>
        </div>
      </div>
    </div>
  );
};

export default LiveAssistant;
