'use client';

import { useState, useRef, useEffect, useCallback, Suspense } from 'react';
import { useSearchParams } from 'next/navigation';
import { motion, AnimatePresence } from 'framer-motion';
import { Mic, MicOff, Volume2, VolumeX, Ghost, Loader2, MessageSquare, ArrowLeft, ShieldX, Upload, Camera, BookOpen, X, FileText, Send, ImageIcon } from 'lucide-react';
import Link from 'next/link';
import Image from 'next/image';
import { BRAND } from '@/lib/white-label/constants';

interface Message {
  role: 'user' | 'assistant';
  content: string;
  image?: string;
}

interface UserInfo {
  userId: string;
  name: string;
  permissions: string[];
}

interface FileContext {
  name: string;
  type: string;
  preview: string;
  isImage?: boolean;
  imageData?: string; // base64 for images
}

function TalkToTesContent() {
  const searchParams = useSearchParams();
  const [isAuthorized, setIsAuthorized] = useState<boolean | null>(null);
  const [userInfo, setUserInfo] = useState<UserInfo | null>(null);
  const [isListening, setIsListening] = useState(false);
  const [isSpeaking, setIsSpeaking] = useState(false);
  const [isProcessing, setIsProcessing] = useState(false);
  const [isMuted, setIsMuted] = useState(false);
  const [transcript, setTranscript] = useState('');
  const [messages, setMessages] = useState<Message[]>([]);
  const [error, setError] = useState<string | null>(null);
  const [isSupported, setIsSupported] = useState(true);
  const [uploadedFile, setUploadedFile] = useState<FileContext | null>(null);
  const [fashionPhoto, setFashionPhoto] = useState<string | null>(null);
  const [isLoadingFashion, setIsLoadingFashion] = useState(false);
  const [textInput, setTextInput] = useState('');
  
  const recognitionRef = useRef<any>(null);
  const audioRef = useRef<HTMLAudioElement | null>(null);
  const messagesEndRef = useRef<HTMLDivElement>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const tokenRef = useRef<string | null>(null);

  // Verify token on mount
  useEffect(() => {
    const token = searchParams.get('token');
    if (!token) {
      setIsAuthorized(false);
      return;
    }
    
    tokenRef.current = token;
    
    fetch('/api/tes-auth', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ token })
    })
      .then(res => res.json())
      .then(data => {
        if (data.valid === true) {
          setIsAuthorized(true);
          setUserInfo({
            userId: data.userId,
            name: data.name,
            permissions: data.permissions
          });
        } else {
          setIsAuthorized(false);
        }
      })
      .catch(() => setIsAuthorized(false));
  }, [searchParams]);

  // Check browser support
  useEffect(() => {
    if (isAuthorized !== true) return;
    const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;
    if (!SpeechRecognition) {
      setIsSupported(false);
      setError('Speech recognition not supported in this browser. Please use Chrome.');
    }
  }, [isAuthorized]);
  
  // Helper to check permissions
  const hasPermission = (perm: string) => {
    return userInfo?.permissions.includes(perm) || userInfo?.permissions.includes('admin');
  };

  // Scroll to bottom on new messages
  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [messages]);

  // Handle file upload
  const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>) => {
    const file = event.target.files?.[0];
    if (!file) return;
    
    try {
      let preview = '';
      let isImage = false;
      let imageData = '';
      
      // Check if it's an image
      if (file.type.startsWith('image/')) {
        isImage = true;
        // Convert image to base64
        const reader = new FileReader();
        const base64Promise = new Promise<string>((resolve) => {
          reader.onloadend = () => {
            resolve(reader.result as string);
          };
        });
        reader.readAsDataURL(file);
        imageData = await base64Promise;
        preview = '[Image uploaded - I can see and analyze this image]';
        
        setUploadedFile({
          name: file.name,
          type: file.type,
          preview,
          isImage: true,
          imageData
        });
        
        // Add a message with the image preview
        setMessages(prev => [...prev, { 
          role: 'assistant', 
          content: `I can see your image "${file.name}". What would you like me to help you with? I can analyze what's in it, answer questions about it, or help you with whatever you need.`,
          image: imageData
        }]);
      } else {
        // Read file content for text-based files
        if (file.type.includes('text') || file.name.endsWith('.csv') || file.name.endsWith('.json') || file.name.endsWith('.md')) {
          const text = await file.text();
          preview = text.substring(0, 2000); // First 2000 chars
        } else if (file.type.includes('spreadsheet') || file.name.endsWith('.xlsx') || file.name.endsWith('.xls')) {
          preview = '[Spreadsheet file - please describe what you need help with]';
        } else if (file.type.includes('pdf')) {
          preview = '[PDF file - please describe what you need help with]';
        } else {
          preview = '[Binary file - please describe what you need help with]';
        }
        
        setUploadedFile({
          name: file.name,
          type: file.type || 'unknown',
          preview
        });
        
        // Add a system message about the upload
        setMessages(prev => [...prev, { 
          role: 'assistant', 
          content: `I see you've uploaded "${file.name}". What would you like me to help you with?` 
        }]);
      }
    } catch (err) {
      setError('Failed to read file');
    }
    
    // Reset input
    if (fileInputRef.current) {
      fileInputRef.current.value = '';
    }
  };
  
  // Handle fashion photo request
  const handleFashionPhoto = async () => {
    if (!hasPermission('fashion')) return;
    
    setIsLoadingFashion(true);
    try {
      const response = await fetch('/api/tes-fashion', {
        method: 'POST',
        headers: { 
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${tokenRef.current}`
        },
        body: JSON.stringify({})
      });
      
      if (response.ok) {
        const { photo } = await response.json();
        if (photo?.imageUrl) {
          setFashionPhoto(photo.imageUrl);
          setMessages(prev => [...prev, { 
            role: 'assistant', 
            content: `Here's today's fashion photo for you, Scott. Style: ${photo.style || 'surprise'}`,
            image: photo.imageUrl
          }]);
        }
      } else {
        setError('Could not generate fashion photo');
      }
    } catch (err) {
      setError('Failed to generate fashion photo');
    } finally {
      setIsLoadingFashion(false);
    }
  };

  const sendToTes = useCallback(async (userMessage: string) => {
    if (!userMessage.trim()) return;

    // Add user message
    const newMessages: Message[] = [...messages, { role: 'user', content: userMessage }];
    setMessages(newMessages);
    setIsProcessing(true);
    setError(null);

    try {
      // Build request payload
      const payload: any = {
        message: userMessage,
        history: newMessages.slice(-10).map(m => ({ role: m.role, content: m.content })),
        userId: userInfo?.userId,
        userName: userInfo?.name,
        permissions: userInfo?.permissions,
        fileContext: uploadedFile ? { name: uploadedFile.name, type: uploadedFile.type, preview: uploadedFile.preview } : null
      };
      
      // Include image data if an image was uploaded
      if (uploadedFile?.isImage && uploadedFile?.imageData) {
        payload.imageData = uploadedFile.imageData;
      }
      
      // Get Tes's response
      const chatResponse = await fetch('/api/tes-chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload)
      });

      if (!chatResponse.ok) {
        const errorData = await chatResponse.json().catch(() => ({}));
        throw new Error(errorData.error || `Server responded with ${chatResponse.status}`);
      }
      
      const { reply, imageUrl } = await chatResponse.json();
      
      // Add assistant message (with generated image if present)
      setMessages(prev => [...prev, { 
        role: 'assistant', 
        content: reply,
        image: imageUrl || undefined
      }]);
      
      // Clear image from file context after sending (but keep text files)
      if (uploadedFile?.isImage) {
        setUploadedFile(null);
      }

      // Get TTS audio if not muted
      if (!isMuted) {
        setIsSpeaking(true);
        const ttsResponse = await fetch('/api/tts', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ text: reply })
        });

        if (ttsResponse.ok) {
          const audioBlob = await ttsResponse.blob();
          const audioUrl = URL.createObjectURL(audioBlob);
          
          if (audioRef.current) {
            // Clean up previous audio URL to prevent memory leaks and overlapping audio
            if (audioRef.current.src && audioRef.current.src.startsWith('blob:')) {
              URL.revokeObjectURL(audioRef.current.src);
            }
            audioRef.current.src = audioUrl;
            audioRef.current.play();
          }
        } else {
          setIsSpeaking(false);
        }
      }
    } catch (err) {
      console.error('Error:', err);
      const errorMessage = err instanceof Error ? err.message : 'Unknown error';
      setError(`Communication error: ${errorMessage}`);
    } finally {
      setIsProcessing(false);
    }
  }, [messages, isMuted, userInfo, uploadedFile]);

  const startListening = useCallback(() => {
    const SpeechRecognition = (window as any).SpeechRecognition || (window as any).webkitSpeechRecognition;
    if (!SpeechRecognition) return;

    const recognition = new SpeechRecognition();
    recognition.continuous = false;
    recognition.interimResults = true;
    recognition.lang = 'en-US';

    recognition.onstart = () => {
      setIsListening(true);
      setTranscript('');
    };

    recognition.onresult = (event: any) => {
      let finalTranscript = '';
      let interimTranscript = '';

      for (let i = event.resultIndex; i < event.results.length; i++) {
        const transcript = event.results[i][0].transcript;
        if (event.results[i].isFinal) {
          finalTranscript += transcript;
        } else {
          interimTranscript += transcript;
        }
      }

      setTranscript(finalTranscript || interimTranscript);

      if (finalTranscript) {
        sendToTes(finalTranscript);
      }
    };

    recognition.onerror = (event: any) => {
      console.error('Speech recognition error:', event.error);
      setIsListening(false);
      if (event.error !== 'no-speech') {
        setError(`Speech recognition error: ${event.error}`);
      }
    };

    recognition.onend = () => {
      setIsListening(false);
    };

    recognitionRef.current = recognition;
    recognition.start();
  }, [sendToTes]);

  const stopListening = useCallback(() => {
    if (recognitionRef.current) {
      recognitionRef.current.stop();
    }
    setIsListening(false);
  }, []);

  const handleAudioEnded = () => {
    setIsSpeaking(false);
    // Clean up the blob URL after playback
    if (audioRef.current?.src && audioRef.current.src.startsWith('blob:')) {
      URL.revokeObjectURL(audioRef.current.src);
    }
  };

  const toggleMute = () => {
    setIsMuted(!isMuted);
    if (audioRef.current && !isMuted) {
      audioRef.current.pause();
      setIsSpeaking(false);
    }
  };
  
  const handleTextSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    if (textInput.trim() && !isProcessing) {
      sendToTes(textInput.trim());
      setTextInput('');
    }
  };

  // Loading state
  if (isAuthorized === null) {
    return (
      <div className="min-h-screen bg-brand-bg text-white flex items-center justify-center">
        <Loader2 className="w-8 h-8 animate-spin text-brand" />
      </div>
    );
  }

  // Unauthorized
  if (isAuthorized === false) {
    return (
      <div className="min-h-screen bg-brand-bg text-white flex flex-col items-center justify-center p-6">
        <ShieldX className="w-16 h-16 text-red-500 mb-4" />
        <h1 className="text-2xl font-bold mb-2">Access Denied</h1>
        <p className="text-gray-400 text-center max-w-md">
          This is a private channel. You need a valid access token to talk to Tes.
        </p>
        <Link href="/" className="mt-6 text-brand hover:underline">
          ← Return to {BRAND.primaryName}
        </Link>
      </div>
    );
  }

  return (
    <div className="min-h-screen bg-brand-bg text-white flex flex-col">
      {/* Header */}
      <header className="border-b border-white/10 p-4">
        <div className="max-w-4xl mx-auto flex items-center justify-between">
          <Link href="/" className="flex items-center gap-2 text-gray-400 hover:text-white transition-colors">
            <ArrowLeft className="w-5 h-5" />
            <span>Back</span>
          </Link>
          <div className="flex items-center gap-3">
            <Ghost className="w-8 h-8 text-brand" />
            <div className="text-center">
              <h1 className="text-xl font-bold gradient-text">Talk to Tes</h1>
              {userInfo && <p className="text-xs text-gray-400">Hello, {userInfo.name}</p>}
            </div>
          </div>
          <div className="flex items-center gap-2">
            {/* Fashion photo button - only for users with permission */}
            {hasPermission('fashion') && (
              <button
                onClick={handleFashionPhoto}
                disabled={isLoadingFashion}
                className="p-2 rounded-lg hover:bg-white/10 transition-colors disabled:opacity-50"
                title="Get today's fashion photo"
              >
                {isLoadingFashion ? (
                  <Loader2 className="w-5 h-5 animate-spin text-pink-400" />
                ) : (
                  <Camera className="w-5 h-5 text-pink-400" />
                )}
              </button>
            )}
            
            {/* File upload button */}
            {hasPermission('upload') && (
              <>
                <input
                  ref={fileInputRef}
                  type="file"
                  onChange={handleFileUpload}
                  className="hidden"
                  accept=".txt,.csv,.json,.md,.pdf,.xlsx,.xls,.doc,.docx,image/*"
                />
                <button
                  onClick={() => fileInputRef.current?.click()}
                  className="p-2 rounded-lg hover:bg-white/10 transition-colors"
                  title="Upload a file or image"
                >
                  <Upload className="w-5 h-5 text-green-400" />
                </button>
              </>
            )}
            
            <button
              onClick={toggleMute}
              className="p-2 rounded-lg hover:bg-white/10 transition-colors"
              title={isMuted ? 'Unmute' : 'Mute'}
            >
              {isMuted ? <VolumeX className="w-5 h-5 text-gray-400" /> : <Volume2 className="w-5 h-5 text-brand" />}
            </button>
          </div>
        </div>
      </header>
      
      {/* File context indicator */}
      {uploadedFile && (
        <div className={`${uploadedFile.isImage ? 'bg-brand-secondary/10 border-brand-secondary/30' : 'bg-green-500/10 border-green-500/30'} border-b px-4 py-2`}>
          <div className="max-w-4xl mx-auto flex items-center justify-between">
            <div className="flex items-center gap-3 text-sm">
              {uploadedFile.isImage && uploadedFile.imageData ? (
                <>
                  <div className="relative w-10 h-10 rounded overflow-hidden">
                    <Image 
                      src={uploadedFile.imageData} 
                      alt="Uploaded preview" 
                      fill 
                      className="object-cover"
                      unoptimized
                    />
                  </div>
                  <span className="text-brand-secondary-light">Image ready: {uploadedFile.name}</span>
                </>
              ) : (
                <>
                  <FileText className="w-4 h-4 text-green-400" />
                  <span className="text-green-400">File loaded: {uploadedFile.name}</span>
                </>
              )}
            </div>
            <button
              onClick={() => setUploadedFile(null)}
              className="p-1 hover:bg-white/10 rounded"
            >
              <X className="w-4 h-4 text-gray-400" />
            </button>
          </div>
        </div>
      )}

      {/* Main content */}
      <main className="flex-1 flex flex-col max-w-4xl mx-auto w-full p-4">
        {/* Messages */}
        <div className="flex-1 overflow-y-auto space-y-4 mb-4">
          {messages.length === 0 && (
            <div className="text-center py-12">
              <Ghost className="w-16 h-16 mx-auto text-brand/50 mb-4" />
              <p className="text-gray-400">Press the mic button and start talking.</p>
              <p className="text-gray-500 text-sm mt-2">I&apos;ll respond with voice.</p>
            </div>
          )}
          
          <AnimatePresence>
            {messages.map((msg, i) => (
              <motion.div
                key={i}
                initial={{ opacity: 0, y: 10 }}
                animate={{ opacity: 1, y: 0 }}
                className={`flex ${msg.role === 'user' ? 'justify-end' : 'justify-start'}`}
              >
                <div
                  className={`max-w-[80%] p-4 rounded-2xl ${
                    msg.role === 'user'
                      ? 'bg-brand-secondary-deep/30 border border-brand-secondary/30'
                      : 'bg-brand-deep/20 border border-brand-deep/30'
                  }`}
                >
                  <p className="text-white">{msg.content}</p>
                  {msg.image && (
                    <div className="mt-3 relative aspect-square max-w-xs rounded-lg overflow-hidden">
                      <Image 
                        src={msg.image} 
                        alt="Tes fashion photo"
                        fill
                        className="object-cover"
                        unoptimized
                      />
                    </div>
                  )}
                </div>
              </motion.div>
            ))}
          </AnimatePresence>
          <div ref={messagesEndRef} />
        </div>

        {/* Transcript preview */}
        {(isListening || transcript) && (
          <div className="mb-4 p-3 rounded-lg bg-white/5 border border-white/10">
            <p className="text-gray-400 text-sm">
              {isListening ? '🎤 Listening...' : ''} {transcript}
            </p>
          </div>
        )}

        {/* Error display */}
        {error && (
          <div className="mb-4 p-3 rounded-lg bg-red-500/20 border border-red-500/30">
            <p className="text-red-400 text-sm">{error}</p>
          </div>
        )}

        {/* Text Input Form */}
        <form onSubmit={handleTextSubmit} className="flex gap-2 mb-4">
          <input
            type="text"
            value={textInput}
            onChange={(e) => setTextInput(e.target.value)}
            placeholder="Type a message..."
            disabled={isProcessing}
            className="flex-1 px-4 py-3 rounded-xl bg-white/5 border border-white/20 text-white placeholder-gray-500 focus:outline-none focus:border-brand-deep focus:ring-1 focus:ring-brand-deep disabled:opacity-50"
          />
          <button
            type="submit"
            disabled={isProcessing || !textInput.trim()}
            className="px-4 py-3 rounded-xl bg-gradient-to-r from-brand-deep to-brand-secondary-deep hover:from-brand hover:to-brand-secondary disabled:opacity-50 disabled:cursor-not-allowed transition-all"
          >
            {isProcessing ? <Loader2 className="w-5 h-5 animate-spin" /> : <Send className="w-5 h-5" />}
          </button>
        </form>

        {/* Voice Controls */}
        <div className="flex justify-center items-center gap-4 py-4">
          {isSupported && (
            <button
              onClick={isListening ? stopListening : startListening}
              disabled={isProcessing}
              className={`relative p-5 rounded-full transition-all duration-300 ${
                isListening
                  ? 'bg-red-500 hover:bg-red-600 animate-pulse'
                  : isProcessing
                  ? 'bg-gray-600 cursor-not-allowed'
                  : 'bg-white/10 hover:bg-white/20 border border-white/20'
              }`}
              title={isListening ? 'Stop listening' : 'Start voice input'}
            >
              {isProcessing ? (
                <Loader2 className="w-6 h-6 animate-spin" />
              ) : isListening ? (
                <MicOff className="w-6 h-6" />
              ) : (
                <Mic className="w-6 h-6 text-brand" />
              )}
              
              {/* Pulse rings when listening */}
              {isListening && (
                <>
                  <span className="absolute inset-0 rounded-full bg-red-500 animate-ping opacity-50" />
                  <span className="absolute -inset-2 rounded-full border-2 border-red-400 animate-pulse" />
                </>  
              )}
              
              {/* Speaking indicator */}
              {isSpeaking && (
                <span className="absolute -inset-3 rounded-full border-2 border-brand animate-pulse" />
              )}
            </button>
          )}
        </div>

        {/* Status */}
        <div className="text-center text-sm text-gray-500">
          {isSpeaking ? (
            <span className="text-brand">Tes is speaking...</span>
          ) : isProcessing ? (
            <span className="text-brand-secondary-light">Thinking...</span>
          ) : isListening ? (
            <span className="text-red-400">Listening...</span>
          ) : (
            <span>Tap the mic to talk</span>
          )}
        </div>
      </main>

      {/* Hidden audio element */}
      <audio
        ref={audioRef}
        onEnded={handleAudioEnded}
        onError={() => setIsSpeaking(false)}
      />
    </div>
  );
}

export default function TalkToTes() {
  return (
    <Suspense fallback={
      <div className="min-h-screen bg-brand-bg text-white flex items-center justify-center">
        <Loader2 className="w-8 h-8 animate-spin text-brand" />
      </div>
    }>
      <TalkToTesContent />
    </Suspense>
  );
}
