import { useState, useRef, useEffect } from 'react';
import { motion } from 'framer-motion';
import { Send, Bot, User, Loader2, Trash2, AlertTriangle, Maximize2, Minimize2, ChevronDown, Settings } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Textarea } from '@/components/ui/textarea';
import { ScrollArea } from '@/components/ui/scroll-area';
import { useSettings } from '@/contexts/SettingsContext';
import { useAchievements, incrementAiMessageCount } from '@/contexts/AchievementsContext';
import { useToast } from '@/hooks/use-toast';
import GlitchText from '@/components/GlitchText';
import MessageContent from '@/components/MessageContent';
import { AI_PROVIDERS, AIProvider, getProvider, CUSTOM_API_STORAGE_KEY } from '@/lib/aiProviders';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';

interface Message {
  id: string;
  role: 'user' | 'assistant' | 'system';
  content: string;
  timestamp: Date;
}

interface CustomApiConfig {
  endpoint: string;
  apiKey: string;
  model: string;
}

const STORAGE_KEY = 'ai-chat-history';
const PROVIDER_KEY = 'ai-chat-provider';

const AIChat = () => {
  const [messages, setMessages] = useState<Message[]>(() => {
    const stored = localStorage.getItem(STORAGE_KEY);
    if (stored) {
      try {
        const parsed = JSON.parse(stored);
        return parsed.map((msg: Message) => ({
          ...msg,
          timestamp: new Date(msg.timestamp),
        }));
      } catch {
        return [];
      }
    }
    return [];
  });
  const [input, setInput] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const [isFullscreen, setIsFullscreen] = useState(false);
  const [selectedProvider, setSelectedProvider] = useState<AIProvider>(() => {
    const stored = localStorage.getItem(PROVIDER_KEY);
    return (stored as AIProvider) || 'pollinations';
  });
  const [customApiConfig, setCustomApiConfig] = useState<CustomApiConfig>(() => {
    const stored = localStorage.getItem(CUSTOM_API_STORAGE_KEY);
    if (stored) {
      try {
        return JSON.parse(stored);
      } catch {
        return { endpoint: '', apiKey: '', model: '' };
      }
    }
    return { endpoint: '', apiKey: '', model: '' };
  });
  const [showCustomApiDialog, setShowCustomApiDialog] = useState(false);
  const [tempCustomConfig, setTempCustomConfig] = useState<CustomApiConfig>({ endpoint: '', apiKey: '', model: '' });
  const scrollRef = useRef<HTMLDivElement>(null);
  const { playSound } = useSettings();
  const { checkAiAchievements } = useAchievements();
  const { toast } = useToast();

  // Persist messages to localStorage
  useEffect(() => {
    if (messages.length > 0) {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(messages));
    } else {
      localStorage.removeItem(STORAGE_KEY);
    }
  }, [messages]);

  // Persist provider selection
  useEffect(() => {
    localStorage.setItem(PROVIDER_KEY, selectedProvider);
  }, [selectedProvider]);

  // Persist custom API config
  useEffect(() => {
    if (customApiConfig.endpoint || customApiConfig.apiKey) {
      localStorage.setItem(CUSTOM_API_STORAGE_KEY, JSON.stringify(customApiConfig));
    }
  }, [customApiConfig]);

  // Exit fullscreen on Escape key
  useEffect(() => {
    const handleEscape = (e: KeyboardEvent) => {
      if (e.key === 'Escape' && isFullscreen) {
        setIsFullscreen(false);
        playSound('click');
      }
    };
    window.addEventListener('keydown', handleEscape);
    return () => window.removeEventListener('keydown', handleEscape);
  }, [isFullscreen, playSound]);

  useEffect(() => {
    if (scrollRef.current) {
      scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
    }
  }, [messages]);

  const sendMessage = async () => {
    if (!input.trim() || isLoading) return;

    const userMessage: Message = {
      id: Date.now().toString(),
      role: 'user',
      content: input.trim(),
      timestamp: new Date(),
    };

    setMessages(prev => [...prev, userMessage]);
    setInput('');
    setIsLoading(true);
    playSound('click');
    
    // Track AI message count for achievements
    incrementAiMessageCount();
    checkAiAchievements();

    try {
      // Build chat history, filtering out empty messages, system notices, and ensuring proper alternation
      const validMessages = messages.filter(msg => msg.content.trim() !== '' && msg.role !== 'system');
      let chatHistory: { role: 'user' | 'assistant'; content: string }[] = [];
      
      for (const msg of validMessages) {
        // Avoid consecutive same-role messages by merging or skipping
        if (chatHistory.length > 0 && chatHistory[chatHistory.length - 1].role === msg.role) {
          // Merge consecutive same-role messages
          chatHistory[chatHistory.length - 1].content += '\n' + msg.content;
        } else if (msg.role === 'user' || msg.role === 'assistant') {
          chatHistory.push({ role: msg.role, content: msg.content });
        }
      }

      // Add the new user message
      if (chatHistory.length > 0 && chatHistory[chatHistory.length - 1].role === 'user') {
        chatHistory[chatHistory.length - 1].content += '\n' + userMessage.content;
      } else {
        chatHistory.push({ role: 'user', content: userMessage.content });
      }

      // Truncate history to stay within API character limits (max ~5000 chars to be safe)
      const MAX_CHARS = 5000;
      const systemPromptLength = 100; // approximate system prompt length
      let totalChars = systemPromptLength;
      
      // Keep messages from the end (most recent) until we hit the limit
      const truncatedHistory: typeof chatHistory = [];
      const originalLength = chatHistory.length;
      for (let i = chatHistory.length - 1; i >= 0; i--) {
        const msgLength = chatHistory[i].content.length;
        if (totalChars + msgLength > MAX_CHARS && truncatedHistory.length > 0) {
          break;
        }
        totalChars += msgLength;
        truncatedHistory.unshift(chatHistory[i]);
      }
      
      // Check if truncation occurred and notify user
      const wasTruncated = truncatedHistory.length < originalLength;
      if (wasTruncated) {
        const systemNotice: Message = {
          id: `system-${Date.now()}`,
          role: 'system',
          content: '⚠ Memory limit reached. Earlier conversation context has been cleared. The AI may not remember previous topics.',
          timestamp: new Date(),
        };
        setMessages(prev => [...prev, systemNotice]);
      }
      
      chatHistory = truncatedHistory;

      const assistantMessage: Message = {
        id: (Date.now() + 1).toString(),
        role: 'assistant',
        content: '',
        timestamp: new Date(),
      };

      setMessages(prev => [...prev, assistantMessage]);

      // Helper function to make API request with retry logic
      const provider = getProvider(selectedProvider);
      
      // For custom provider, use user's config
      const apiEndpoint = selectedProvider === 'custom' ? customApiConfig.endpoint : provider.endpoint;
      const apiKey = selectedProvider === 'custom' ? customApiConfig.apiKey : provider.apiKey;
      const apiModel = selectedProvider === 'custom' ? customApiConfig.model : provider.model;
      
      if (selectedProvider === 'custom' && (!customApiConfig.endpoint || !customApiConfig.apiKey)) {
        toast({
          title: 'Custom API not configured',
          description: 'Please configure your custom API settings first.',
          variant: 'destructive',
        });
        setMessages(prev => prev.filter(msg => msg.id !== assistantMessage.id));
        setIsLoading(false);
        return;
      }

      const makeRequest = async (retries = 3, delay = 1000): Promise<Response> => {
        for (let attempt = 1; attempt <= retries; attempt++) {
          try {
            const headers: Record<string, string> = {
              'Content-Type': 'application/json',
            };
            
            if ((provider.requiresAuth || selectedProvider === 'custom') && apiKey) {
              headers['Authorization'] = `Bearer ${apiKey}`;
            }

            const response = await fetch(apiEndpoint, {
              method: 'POST',
              headers,
              body: JSON.stringify({
                model: apiModel,
                messages: [
                  { role: 'system', content: 'You are a helpful AI assistant with a hacker/cyberpunk personality. Keep responses concise and engaging. IMPORTANT: When sharing code examples, ALWAYS wrap them in markdown code blocks with the language specified, like ```python\ncode here\n``` or ```javascript\ncode here\n```. Never show code without proper markdown code block formatting.' },
                  ...chatHistory,
                ],
                stream: true,
              }),
            });

            if (response.ok) {
              return response;
            }

            // If it's a 500 error and we have retries left, wait and try again
            if (response.status >= 500 && attempt < retries) {
              console.log(`API returned ${response.status}, retrying in ${delay}ms (attempt ${attempt}/${retries})`);
              await new Promise(resolve => setTimeout(resolve, delay));
              delay *= 2; // Exponential backoff
              continue;
            }

            throw new Error(`API error: ${response.status}`);
          } catch (error) {
            // Network errors (failed to fetch) - retry if we have attempts left
            if (attempt < retries && error instanceof TypeError) {
              console.log(`Network error, retrying in ${delay}ms (attempt ${attempt}/${retries})`);
              await new Promise(resolve => setTimeout(resolve, delay));
              delay *= 2;
              continue;
            }
            throw error;
          }
        }
        throw new Error('Failed after all retries');
      };

      const response = await makeRequest();

      const reader = response.body?.getReader();
      const decoder = new TextDecoder();

      if (reader) {
        let buffer = '';
        
        while (true) {
          const { done, value } = await reader.read();
          if (done) break;

          buffer += decoder.decode(value, { stream: true });
          
          // Process SSE format
          const lines = buffer.split('\n');
          buffer = lines.pop() || '';

          for (const line of lines) {
            if (line.startsWith('data: ')) {
              const data = line.slice(6).trim();
              if (data === '[DONE]') continue;
              
              try {
                const parsed = JSON.parse(data);
                const content = parsed.choices?.[0]?.delta?.content || '';
                if (content) {
                  setMessages(prev =>
                    prev.map(msg =>
                      msg.id === assistantMessage.id
                        ? { ...msg, content: msg.content + content }
                        : msg
                    )
                  );
                }
              } catch {
                // Not valid JSON, might be plain text
                if (data && data !== '[DONE]') {
                  setMessages(prev =>
                    prev.map(msg =>
                      msg.id === assistantMessage.id
                        ? { ...msg, content: msg.content + data }
                        : msg
                    )
                  );
                }
              }
            }
          }
        }

        // Handle any remaining buffer content
        if (buffer.trim()) {
          setMessages(prev =>
            prev.map(msg =>
              msg.id === assistantMessage.id
                ? { ...msg, content: msg.content + buffer }
                : msg
            )
          );
        }
      }

      playSound('click');
    } catch (error) {
      console.error('AI Chat error:', error);
      toast({
        title: 'Error',
        description: error instanceof Error ? error.message : 'Failed to get AI response',
        variant: 'destructive',
      });
      // Remove the empty assistant message if error occurred
      setMessages(prev => prev.filter(msg => msg.content !== ''));
    } finally {
      setIsLoading(false);
    }
  };

  const clearChat = () => {
    setMessages([]);
    playSound('click');
    toast({
      title: 'Chat Cleared',
      description: 'Conversation history has been erased.',
    });
  };

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      sendMessage();
    }
  };

  const toggleFullscreen = () => {
    setIsFullscreen(!isFullscreen);
    playSound('click');
  };

  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.5 }}
      className={`flex flex-col ${
        isFullscreen 
          ? 'fixed inset-0 z-50 bg-background p-4 md:p-8' 
          : 'h-full'
      }`}
    >
      <div className="flex flex-col sm:flex-row sm:items-center justify-between gap-2 mb-4">
        <GlitchText
          text="AI Terminal"
          className="font-minecraft text-2xl md:text-3xl text-primary text-glow"
        />
        <div className="flex items-center gap-2 flex-wrap">
          <Button
            variant="ghost"
            size="sm"
            onClick={toggleFullscreen}
            className="text-primary hover:bg-primary/20 order-first sm:order-last"
            title={isFullscreen ? 'Exit fullscreen (Esc)' : 'Fullscreen'}
          >
            {isFullscreen ? (
              <Minimize2 className="w-4 h-4" />
            ) : (
              <Maximize2 className="w-4 h-4" />
            )}
          </Button>
          {messages.length > 0 && (
            <>
              <div className="flex items-center gap-2 px-2 py-1 border border-primary/30 rounded text-xs font-pixel">
                <span className="text-muted-foreground">Memory:</span>
                <span className={`${
                  (() => {
                    const totalChars = messages.filter(m => m.role !== 'system').reduce((acc, m) => acc + m.content.length, 0);
                    const percent = (totalChars / 5000) * 100;
                    return percent > 80 ? 'text-red-400' : percent > 50 ? 'text-yellow-400' : 'text-green-400';
                  })()
                }`}>
                  {Math.min(100, Math.round((messages.filter(m => m.role !== 'system').reduce((acc, m) => acc + m.content.length, 0) / 5000) * 100))}%
                </span>
              </div>
              <Button
                variant="ghost"
                size="sm"
                onClick={clearChat}
                className="text-primary hover:bg-primary/20"
              >
                <Trash2 className="w-4 h-4 mr-2" />
                Clear
              </Button>
            </>
          )}
        </div>
      </div>

      <div className="flex items-center gap-2 mb-4">
        <span className="text-muted-foreground font-pixel text-sm">{'>'} Model:</span>
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button
              variant="ghost"
              size="sm"
              className="text-primary hover:bg-primary/20 font-pixel text-sm gap-1"
            >
              {getProvider(selectedProvider).name}
              <ChevronDown className="w-3 h-3" />
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent className="bg-background border-primary/50">
            {AI_PROVIDERS.map((provider) => (
              <DropdownMenuItem
                key={provider.id}
                onClick={() => {
                  if (provider.id === 'custom') {
                    setTempCustomConfig(customApiConfig);
                    setShowCustomApiDialog(true);
                  }
                  setSelectedProvider(provider.id);
                  playSound('click');
                }}
                className={`font-pixel text-xs cursor-pointer ${
                  selectedProvider === provider.id ? 'text-primary' : 'text-foreground'
                }`}
              >
                <div className="flex items-center gap-2 w-full">
                  <div className="flex-1">
                    <div>{provider.name}</div>
                    <div className="text-muted-foreground text-[10px]">{provider.description}</div>
                  </div>
                  {provider.id === 'custom' && (
                    <Settings className="w-3 h-3 text-muted-foreground" />
                  )}
                </div>
              </DropdownMenuItem>
            ))}
          </DropdownMenuContent>
        </DropdownMenu>
        {selectedProvider === 'custom' && (
          <Button
            variant="ghost"
            size="sm"
            onClick={() => {
              setTempCustomConfig(customApiConfig);
              setShowCustomApiDialog(true);
              playSound('click');
            }}
            className="text-primary hover:bg-primary/20 font-pixel text-xs"
          >
            <Settings className="w-3 h-3 mr-1" />
            Configure
          </Button>
        )}
      </div>

      <ScrollArea className="flex-1 border border-primary/30 rounded-lg p-4 mb-4 bg-background/50" ref={scrollRef}>
        {messages.length === 0 ? (
          <div className="h-full flex items-center justify-center text-muted-foreground">
            <div className="text-center">
              <Bot className="w-12 h-12 mx-auto mb-4 opacity-50" />
              <p className="font-pixel text-sm">No messages yet.</p>
              <p className="font-pixel text-xs mt-2">Start a conversation with the AI.</p>
            </div>
          </div>
        ) : (
          <div className="space-y-4">
            {messages.map((message, index) => (
              message.role === 'system' ? (
                <motion.div
                  key={message.id}
                  initial={{ opacity: 0, y: -10 }}
                  animate={{ opacity: 1, y: 0 }}
                  className="flex justify-center"
                >
                  <div className="flex items-center gap-2 px-4 py-2 rounded-lg bg-yellow-500/10 border border-yellow-500/30">
                    <AlertTriangle className="w-4 h-4 text-yellow-500" />
                    <p className="font-pixel text-xs text-yellow-500">{message.content}</p>
                  </div>
                </motion.div>
              ) : (
                <motion.div
                  key={message.id}
                  initial={{ opacity: 0, x: message.role === 'user' ? 20 : -20 }}
                  animate={{ opacity: 1, x: 0 }}
                  transition={{ delay: index * 0.05 }}
                  className={`flex gap-3 ${message.role === 'user' ? 'justify-end' : 'justify-start'}`}
                >
                  {message.role === 'assistant' && (
                    <div className="w-8 h-8 rounded border border-primary/50 flex items-center justify-center bg-primary/10 flex-shrink-0">
                      <Bot className="w-4 h-4 text-primary" />
                    </div>
                  )}
                  <div
                    className={`max-w-[80%] p-3 rounded-lg ${
                      message.role === 'user'
                        ? 'bg-primary/20 border border-primary/50'
                        : 'bg-secondary/50 border border-primary/30'
                    }`}
                  >
                    <MessageContent 
                      content={message.content} 
                      isLoading={isLoading && message.role === 'assistant' && message.content === ''} 
                    />
                  </div>
                  {message.role === 'user' && (
                    <div className="w-8 h-8 rounded border border-primary/50 flex items-center justify-center bg-primary/10 flex-shrink-0">
                      <User className="w-4 h-4 text-primary" />
                    </div>
                  )}
                </motion.div>
              )
            ))}
            {isLoading && messages[messages.length - 1]?.role === 'user' && (
              <motion.div
                initial={{ opacity: 0 }}
                animate={{ opacity: 1 }}
                className="flex gap-3 justify-start"
              >
                <div className="w-8 h-8 rounded border border-primary/50 flex items-center justify-center bg-primary/10">
                  <Bot className="w-4 h-4 text-primary" />
                </div>
                <div className="p-3 rounded-lg bg-secondary/50 border border-primary/30">
                  <Loader2 className="w-4 h-4 text-primary animate-spin" />
                </div>
              </motion.div>
            )}
          </div>
        )}
      </ScrollArea>

      <div className="flex gap-2">
        <Textarea
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onKeyDown={handleKeyDown}
          placeholder="Type your message..."
          disabled={isLoading}
          className="resize-none font-pixel text-sm bg-background/50 border-primary/50 text-primary placeholder:text-muted-foreground focus:border-primary"
          rows={2}
        />
        <Button
          onClick={sendMessage}
          disabled={!input.trim() || isLoading}
          className="px-4 bg-primary/20 border border-primary hover:bg-primary/30 text-primary"
        >
          {isLoading ? (
            <Loader2 className="w-5 h-5 animate-spin" />
          ) : (
            <Send className="w-5 h-5" />
          )}
        </Button>
      </div>

      {/* Custom API Configuration Dialog */}
      <Dialog open={showCustomApiDialog} onOpenChange={setShowCustomApiDialog}>
        <DialogContent className="bg-background border-primary/50">
          <DialogHeader>
            <DialogTitle className="font-pixel text-primary">Custom API Configuration</DialogTitle>
          </DialogHeader>
          <div className="space-y-4 py-4">
            <div className="space-y-2">
              <Label htmlFor="endpoint" className="font-pixel text-sm">API Endpoint</Label>
              <Input
                id="endpoint"
                placeholder="https://api.example.com/v1/chat/completions"
                value={tempCustomConfig.endpoint}
                onChange={(e) => setTempCustomConfig(prev => ({ ...prev, endpoint: e.target.value }))}
                className="font-pixel text-sm bg-background/50 border-primary/50"
              />
            </div>
            <div className="space-y-2">
              <Label htmlFor="apiKey" className="font-pixel text-sm">API Key</Label>
              <Input
                id="apiKey"
                type="password"
                placeholder="sk-..."
                value={tempCustomConfig.apiKey}
                onChange={(e) => setTempCustomConfig(prev => ({ ...prev, apiKey: e.target.value }))}
                className="font-pixel text-sm bg-background/50 border-primary/50"
              />
            </div>
            <div className="space-y-2">
              <Label htmlFor="model" className="font-pixel text-sm">Model Name</Label>
              <Input
                id="model"
                placeholder="gpt-4, claude-3, etc."
                value={tempCustomConfig.model}
                onChange={(e) => setTempCustomConfig(prev => ({ ...prev, model: e.target.value }))}
                className="font-pixel text-sm bg-background/50 border-primary/50"
              />
            </div>
            <p className="text-xs text-muted-foreground font-pixel">
              Your API key is stored locally in your browser and never sent to our servers.
            </p>
          </div>
          <DialogFooter>
            <Button
              variant="ghost"
              onClick={() => setShowCustomApiDialog(false)}
              className="font-pixel text-sm"
            >
              Cancel
            </Button>
            <Button
              onClick={() => {
                setCustomApiConfig(tempCustomConfig);
                setShowCustomApiDialog(false);
                playSound('click');
                toast({
                  title: 'Configuration Saved',
                  description: 'Custom API settings have been updated.',
                });
              }}
              className="font-pixel text-sm bg-primary/20 border border-primary hover:bg-primary/30 text-primary"
            >
              Save
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </motion.div>
  );
};

export default AIChat;
