import { useState, useRef, useEffect } from "react";
import { Send, Plus, PanelLeft, Bot } from "lucide-react";
import { Button } from "@/components/ui/button";
import { apiService, Message as APIMessage } from "@/services/apiService";
import { toast } from "@/components/ui/sonner";
import { ChatBubble } from "@/components/chat/ChatBubble";
import { Separator } from "@/components/ui/separator";
import { cn } from "@/lib/utils";
import { storage, STORAGE_KEYS } from "@/lib/storage";
import { Message, Chat } from "@/types/chat";
import { ProfileModal } from "../modals/ProfileModal";
import { ChatSidebar } from "./ChatSidebar";
import { ChatInputArea } from "./ChatInputArea";
import { WelcomeScreen } from "./WelcomeScreen";
import { DeleteChatDialog } from "./DeleteChatDialog";

interface ChatInterfaceProps {
  onOpenSettings: () => void;
  onOpenSources: () => void;
}

const WELCOME_MESSAGE = "Hello! I'm Insight AI, How can I help you today?";

const generateId = () => Math.random().toString(36).substring(2, 11);

export const ChatInterface = ({ onOpenSettings, onOpenSources }: ChatInterfaceProps) => {
  const [chats, setChats] = useState<Chat[]>(() => {
    const savedChats = storage.get<Chat[]>(STORAGE_KEYS.CHATS);
    if (savedChats) {
      try {
        return savedChats.map((chat: any) => ({
          ...chat,
          messages: chat.messages.map((msg: any) => ({
            ...msg,
            timestamp: new Date(msg.timestamp),
            sender: msg.sender as "user" | "system"
          })),
          createdAt: new Date(chat.createdAt),
          updatedAt: new Date(chat.updatedAt)
        }));
      } catch (error) {
        console.error("Failed to parse saved chats:", error);
        return [];
      }
    }
    return [];
  });

  const [activeChat, setActiveChat] = useState<Chat | null>(() => {
    if (chats.length > 0) {
      return chats[0];
    }
  });

  const [inputValue, setInputValue] = useState("");
  const [isLoading, setIsLoading] = useState(false);
  const [isSidebarOpen, setIsSidebarOpen] = useState(false);
  const [isGeneratingTitle, setIsGeneratingTitle] = useState(false);
  const [isProfileModalOpen, setIsProfileModalOpen] = useState(false);
  const [chatToDelete, setChatToDelete] = useState<string | null>(null);

  const messagesEndRef = useRef<HTMLDivElement>(null);
  const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    // Save chats to storage whenever they change
    if (activeChat && !chats.find(chat => chat.id === activeChat.id)) {
      setChats([activeChat, ...chats]);
    }

    const allChats = activeChat
      ? [
        activeChat,
        ...chats.filter(chat => chat.id !== activeChat.id)
      ]
      : chats;

    storage.set(STORAGE_KEYS.CHATS, allChats);
  }, [chats, activeChat]);

  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
  };

  useEffect(() => {
    scrollToBottom();
  }, [activeChat?.messages]);

  useEffect(() => {
    // Focus input when component mounts or when loading ends
    if (!isLoading) {
      setTimeout(() => {
        inputRef.current?.focus();
      }, 100);
    }
  }, [isLoading]);

  // Handle new chat and chat selection events
  useEffect(() => {
    const handleNewChat = () => createNewChat();
    const handleSelectChat = (e: Event) => {
      const customEvent = e as CustomEvent;
      const chatId = customEvent.detail?.chatId;
      if (chatId) {
        selectChat(chatId);
      }
    };
    const handleDeleteChat = (e: Event) => {
      const customEvent = e as CustomEvent;
      const chatId = customEvent.detail?.chatId;
      if (chatId) {
        setChatToDelete(chatId);
      }
    };

    document.addEventListener("insight:new-chat", handleNewChat);
    document.addEventListener("insight:select-chat", handleSelectChat);
    document.addEventListener("insight:delete-chat", handleDeleteChat);

    return () => {
      document.removeEventListener("insight:new-chat", handleNewChat);
      document.removeEventListener("insight:select-chat", handleSelectChat);
      document.removeEventListener("insight:delete-chat", handleDeleteChat);
    };
  }, [chats, activeChat]);

  const generateChatTitle = async (query: string) => {
    if (!activeChat || activeChat.title !== "New Chat") return;

    setIsGeneratingTitle(true);

    try {
      const response = await apiService.generateTitle(query);

      if (response.title) {
        // Update the active chat with the new title
        setActiveChat(prevChat => {
          if (!prevChat) return null;

          const updatedChat = { ...prevChat, title: response.title };

          // Update chats list
          setChats(prevChats =>
            prevChats.map(chat =>
              chat.id === updatedChat.id ? updatedChat : chat
            )
          );

          return updatedChat;
        });
      }
    } catch (error) {
      console.error("Error generating chat title:", error);
      // Fallback to using query as title
      if (activeChat.title === "New Chat") {
        setActiveChat(prevChat => {
          if (!prevChat) return null;

          const updatedChat = {
            ...prevChat,
            title: query.slice(0, 30) + (query.length > 30 ? '...' : '')
          };

          setChats(prevChats =>
            prevChats.map(chat =>
              chat.id === updatedChat.id ? updatedChat : chat
            )
          );

          return updatedChat;
        });
      }
    } finally {
      setIsGeneratingTitle(false);
    }
  };

  const handleSendMessage = async (e?: React.FormEvent) => {
    if (e) e.preventDefault();

    if (!inputValue.trim() || !activeChat) return;

    const userMessage: Message = {
      id: generateId(),
      content: inputValue,
      sender: "user",
      timestamp: new Date()
    };

    const loadingMessage: Message = {
      id: generateId(),
      content: "",
      sender: "system",
      timestamp: new Date(),
      isLoading: true
    };

    // Update active chat with new messages
    const updatedChat = {
      ...activeChat,
      messages: [...activeChat.messages, userMessage, loadingMessage],
      updatedAt: new Date()
    };

    setActiveChat(updatedChat);
    setInputValue("");
    setIsLoading(true);

    try {
      // Prepare chat history for the API
      const chatHistory: APIMessage[] = updatedChat.messages
        .filter(msg => !msg.isLoading && msg.content) // filter out loading messages
        .slice(0, -1) // exclude the loading message we just added
        .map(msg => ({
          role: msg.sender === "user" ? "user" : "assistant",
          content: msg.content
        }));

      const response = await apiService.queryRulings({
        query: userMessage.content,
        chat_history: chatHistory
      });

      // Replace loading message with actual response
      const updatedMessages = updatedChat.messages.map(msg =>
        msg.id === loadingMessage.id
          ? {
            ...msg,
            content: response.answer,
            isLoading: false,
            result: response.retrieved_sources
          }
          : msg
      );

      const finalChat = {
        ...updatedChat,
        messages: updatedMessages,
      };

      setActiveChat(finalChat);

      // Update chats list
      setChats(prevChats =>
        prevChats.map(chat =>
          chat.id === finalChat.id ? finalChat : chat
        )
      );

      // Generate title if this is a new chat
      if (updatedChat.title === "New Chat" && updatedChat.messages.length <= 3) {
        generateChatTitle(userMessage.content);
      }

    } catch (error) {
      console.error("Error querying AI:", error);

      // Replace loading message with error
      const updatedMessages = updatedChat.messages.map(msg =>
        msg.id === loadingMessage.id
          ? {
            ...msg,
            content: "I'm sorry, I couldn't process your request. Please try again.",
            isLoading: false,
            error: true
          }
          : msg
      );

      setActiveChat({
        ...updatedChat,
        messages: updatedMessages
      });

      toast.error("Failed to process your request");
    } finally {
      setIsLoading(false);
      // Refocus the input after sending message
      setTimeout(() => {
        inputRef.current?.focus();
      }, 100);
    }
  };

  const createNewChat = () => {
    const newChat: Chat = {
      id: generateId(),
      title: "New Chat",
      messages: [
        {
          id: "welcomems",
          content: WELCOME_MESSAGE,
          sender: "system" as const,
          timestamp: new Date()
        }
      ],
      createdAt: new Date(),
      updatedAt: new Date()
    };

    setActiveChat(newChat);
    setChats(prev => [newChat, ...prev]);
    setTimeout(() => {
      inputRef.current?.focus();
    }, 100);
    setIsSidebarOpen(false);
  };

  const selectChat = (chatId: string) => {
    const selectedChat = chats.find(chat => chat.id === chatId);
    if (selectedChat) {
      setActiveChat(selectedChat);
      setIsSidebarOpen(false);
      setTimeout(() => {
        inputRef.current?.focus();
      }, 100);
    }
  };

  const deleteChat = (chatId: string) => {
    const updatedChats = chats.filter(chat => chat.id !== chatId);
    setChats(updatedChats);

    // If we're deleting the active chat, switch to another one
    if (activeChat?.id === chatId) {
      setActiveChat(updatedChats.length > 0 ? updatedChats[0] : null);

      // If no chats left, create a new one
      if (updatedChats.length === 0) {
        createNewChat();
      }
    }
    
    // Clear the chat being deleted
    setChatToDelete(null);
  };

  const handleDeleteMessage = (messageId: string) => {
    if (!activeChat) return;
    
    // Find the index of the message to delete
    const messageIndex = activeChat.messages.findIndex(msg => msg.id === messageId);
    if (messageIndex === -1) return;
    
    // Determine if we need to delete a pair (user message + assistant response)
    const isUserMessage = activeChat.messages[messageIndex].sender === "user";
    const updatedMessages = [...activeChat.messages];
    
    if (isUserMessage && messageIndex + 1 < updatedMessages.length && 
        updatedMessages[messageIndex + 1].sender === "system") {
      // Remove both the user message and the following assistant response
      updatedMessages.splice(messageIndex, 2);
    } else if (!isUserMessage && messageIndex > 0 && 
               updatedMessages[messageIndex - 1].sender === "user") {
      // Remove both the assistant message and the preceding user message
      updatedMessages.splice(messageIndex - 1, 2);
    } else {
      // Just remove the single message
      updatedMessages.splice(messageIndex, 1);
    }
    
    const updatedChat = {
      ...activeChat,
      messages: updatedMessages,
      updatedAt: new Date()
    };
    
    setActiveChat(updatedChat);
    
    // Update chats list
    setChats(prevChats =>
      prevChats.map(chat =>
        chat.id === updatedChat.id ? updatedChat : chat
      )
    );
  };

  const handleRegenerateMessage = (messageId: string) => {
    if (!activeChat) return;
    
    // Find the system message that needs to be regenerated
    const messageIndex = activeChat.messages.findIndex(
      msg => msg.id === messageId && msg.sender === "system"
    );
    
    if (messageIndex < 0) return;
    
    const message = activeChat.messages[messageIndex];
    
    // Find the last user message before this system message
    let userMessageContent = "";
    let userMessageIndex = -1;
    
    for (let i = messageIndex - 1; i >= 0; i--) {
      if (activeChat.messages[i].sender === "user") {
        userMessageContent = activeChat.messages[i].content;
        userMessageIndex = i;
        break;
      }
    }
    
    if (!userMessageContent) return;
    
    // Create a new variation
    const variationId = generateId();
    const now = new Date();
    
    // Prepare the updated message with a loading variation
    const variations = message.variations || [];
    const existingVariations = variations.map(v => ({ ...v }));
    
    // Create a new variations array with the loading state
    const updatedVariations = [
      ...existingVariations,
      { id: variationId, content: "", timestamp: now }
    ];
    
    // Update the message with loading state
    const updatedMessages = [...activeChat.messages];
    updatedMessages[messageIndex] = {
      ...updatedMessages[messageIndex],
      isLoading: true,
      variations: updatedVariations,
      activeVariation: variationId
    };
    
    const updatedChat = {
      ...activeChat,
      messages: updatedMessages
    };
    
    setActiveChat(updatedChat);
    setIsLoading(true);
    
    // Prepare chat history for the API
    // Include only the messages up to the user message that triggered the original response
    const chatHistory: APIMessage[] = activeChat.messages
      .slice(0, userMessageIndex)
      .filter(msg => !msg.isLoading && msg.content)
      .map(msg => ({
        role: msg.sender === "user" ? "user" : "assistant",
        content: msg.content
      }));
    
    // Send the API request
    apiService.queryRulings({
      query: userMessageContent,
      chat_history: chatHistory
    })
      .then(response => {
        // Update the variation with the actual response
        const finalVariations = updatedMessages[messageIndex].variations!.map(v => 
          v.id === variationId 
            ? { ...v, content: response.answer, timestamp: new Date() } 
            : v
        );
        
        const finalMessages = [...updatedMessages];
        finalMessages[messageIndex] = {
          ...finalMessages[messageIndex],
          variations: finalVariations,
          isLoading: false,
          error: false,
          result: response.retrieved_sources,
          activeVariation: variationId
        };
        
        const finalChat = {
          ...updatedChat,
          messages: finalMessages
        };
        
        setActiveChat(finalChat);
        setChats(prevChats =>
          prevChats.map(chat =>
            chat.id === finalChat.id ? finalChat : chat
          )
        );
      })
      .catch(error => {
        console.error("Error regenerating response:", error);
        
        // Remove the failed variation
        const finalVariations = updatedMessages[messageIndex].variations!.filter(v => 
          v.id !== variationId
        );
        
        const finalMessages = [...updatedMessages];
        finalMessages[messageIndex] = {
          ...finalMessages[messageIndex],
          variations: finalVariations,
          isLoading: false,
          activeVariation: finalVariations.length > 0 ? finalVariations[0].id : undefined
        };
        
        setActiveChat({
          ...updatedChat,
          messages: finalMessages
        });
        
        toast.error("Failed to generate variation");
      })
      .finally(() => {
        setIsLoading(false);
        setTimeout(() => {
          inputRef.current?.focus();
        }, 100);
      });
  };

  const handleSelectVariation = (messageId: string, variationId: string) => {
    if (!activeChat) return;

    // Find the message
    const messageIndex = activeChat.messages.findIndex(msg => msg.id === messageId);
    if (messageIndex < 0) return;
    
    // Set the active variation
    const updatedMessages = [...activeChat.messages];
    updatedMessages[messageIndex] = {
      ...updatedMessages[messageIndex],
      activeVariation: variationId
    };
    
    const updatedChat = {
      ...activeChat,
      messages: updatedMessages
    };
    
    setActiveChat(updatedChat);
    
    // Update chats list
    setChats(prevChats =>
      prevChats.map(chat =>
        chat.id === updatedChat.id ? updatedChat : chat
      )
    );
  };

  const handleRetryMessage = (messageId: string) => {
    if (!activeChat) return;

    // Find the failed message
    const failedMessageIndex = activeChat.messages.findIndex(
      msg => msg.id === messageId && msg.error
    );

    if (failedMessageIndex < 0) return;

    // Get the last user message before this failed message
    let userMessageContent = "";
    for (let i = failedMessageIndex - 1; i >= 0; i--) {
      if (activeChat.messages[i].sender === "user") {
        userMessageContent = activeChat.messages[i].content;
        break;
      }
    }

    if (!userMessageContent) return;

    // Remove the failed message
    const updatedMessages = [...activeChat.messages];
    updatedMessages[failedMessageIndex] = {
      ...updatedMessages[failedMessageIndex],
      isLoading: true,
      error: false,
      content: ""
    };

    const updatedChat = {
      ...activeChat,
      messages: updatedMessages
    };

    setActiveChat(updatedChat);
    setIsLoading(true);

    // Prepare chat history for the API
    const chatHistory: APIMessage[] = updatedChat.messages
      .filter(msg => !msg.isLoading && msg.content && updatedChat.messages.indexOf(msg) < failedMessageIndex - 1)
      .map(msg => ({
        role: msg.sender === "user" ? "user" : "assistant",
        content: msg.content
      }));

    // Retry the query
    apiService.queryRulings({
      query: userMessageContent,
      chat_history: chatHistory
    })
      .then(response => {
        const finalMessages = [...updatedMessages];
        finalMessages[failedMessageIndex] = {
          ...finalMessages[failedMessageIndex],
          content: response.answer,
          isLoading: false,
          error: false,
          result: response.retrieved_sources
        };

        const finalChat = {
          ...updatedChat,
          messages: finalMessages
        };

        setActiveChat(finalChat);
        setChats(prevChats =>
          prevChats.map(chat =>
            chat.id === finalChat.id ? finalChat : chat
          )
        );
      })
      .catch(error => {
        console.error("Error retrying query:", error);

        const finalMessages = [...updatedMessages];
        finalMessages[failedMessageIndex] = {
          ...finalMessages[failedMessageIndex],
          content: "I'm sorry, I couldn't process your request. Please try again.",
          isLoading: false,
          error: true
        };

        setActiveChat({
          ...updatedChat,
          messages: finalMessages
        });

        toast.error("Failed to process your request");
      })
      .finally(() => {
        setIsLoading(false);
        setTimeout(() => {
          inputRef.current?.focus();
        }, 100);
      });
  };

  const openProfileModal = () => {
    setIsProfileModalOpen(true);
  };

  return (
    <>
      <div className="flex h-full w-full">
        {/* Chat Sidebar */}
        <ChatSidebar 
          chats={chats}
          activeChat={activeChat}
          isGeneratingTitle={isGeneratingTitle}
          createNewChat={createNewChat}
          selectChat={selectChat}
          onRequestDelete={setChatToDelete}
          onOpenSettings={onOpenSettings}
          onOpenSources={onOpenSources}
          openProfileModal={openProfileModal}
          isSidebarOpen={isSidebarOpen}
          setIsSidebarOpen={setIsSidebarOpen}
        />

        {/* Chat Main Area */}
        <div className="flex-1 flex flex-col overflow-hidden">
          {/* Mobile Header */}
          <div className="md:hidden p-2 flex items-center border-b">
            <Button variant="ghost" size="icon" onClick={() => setIsSidebarOpen(true)}>
              <PanelLeft className="h-5 w-5" />
            </Button>
            <div className="mx-auto font-medium flex items-center">
              <Bot className="h-4 w-4 mr-1.5" />
              {activeChat?.title || "New Chat"}
            </div>
            <Button variant="ghost" size="icon" onClick={createNewChat}>
              <Plus className="h-5 w-5" />
            </Button>
          </div>

          {/* Chat Area */}
          <div className="relative flex-1 overflow-hidden">
            {!activeChat ? (
              <WelcomeScreen onCreateNewChat={createNewChat} />
            ) : (
              <>
                <div className="h-full overflow-y-auto px-4 pb-32 pt-4">
                  <div className="max-w-3xl mx-auto space-y-4">
                    {activeChat.messages.map((message) => (
                      <ChatBubble
                        key={message.id}
                        message={message}
                        onViewSearchResults={onOpenSources}
                        onRetry={handleRetryMessage}
                        onRegenerate={handleRegenerateMessage}
                        onDelete={handleDeleteMessage}
                        onSelectVariation={handleSelectVariation}
                      />
                    ))}
                    <div ref={messagesEndRef} />
                  </div>
                </div>

                {/* Input Area */}
                <ChatInputArea
                  inputRef={inputRef}
                  inputValue={inputValue}
                  setInputValue={setInputValue}
                  handleSendMessage={handleSendMessage}
                  isLoading={isLoading}
                />
              </>
            )}
          </div>
        </div>
      </div>
      
      {/* Profile Modal */}
      <ProfileModal isOpen={isProfileModalOpen} onClose={() => setIsProfileModalOpen(false)} />
      
      {/* Delete Chat Confirmation Dialog */}
      <DeleteChatDialog
        isOpen={chatToDelete !== null}
        onOpenChange={() => setChatToDelete(null)}
        onDelete={() => chatToDelete && deleteChat(chatToDelete)}
      />
    </>
  );
};
