import { FC, useState, useRef, useEffect } from "react";
import { Send, CloseCircle, User, Add, ArrowRight } from "iconsax-react";
import io, { Socket } from "socket.io-client";
import { SOCKET_EVENTS } from "./constants";
import { useSocketHandlers } from "./hooks/useSocketHandlers";
import { useMessages } from "./hooks/useMessages";
import { Message } from "./types";
import { getToken } from "../config/func";
import "./chatbot.css"; // Import CSS for animations
import axios from "axios";

// Helper function to format text with markdown-like syntax
export const formatText = (text: string) => {
  if (!text) return "";

  // Clean the text first to avoid HTML injection
  const cleanedText = text
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");

  // Format with markdown-like syntax and handle newlines properly
  const formattedText = cleanedText
    // Bold text
    .replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
    // Italic text
    .replace(/\*(.*?)\*/g, "<em>$1</em>")
    // Line breaks - ensure they work properly with proper spacing
    .replace(/\n/g, "<br class='message-line-break' />")
    // Links (optional)
    .replace(
      /\[([^\]]+)\]\(([^)]+)\)/g,
      '<a href="$2" target="_blank" rel="noopener noreferrer" class="text-blue-500 underline">$1</a>'
    );

  return formattedText;
};

interface ChatbotProps {
  isOpen: boolean;
  onClose: () => void;
}

// Connection status types
type ConnectionStatus = "disconnected" | "connecting" | "connected" | "error";

// Session type definition
interface ChatSession {
  id: string;
  title: string;
  createdAt: string;
  updatedAt: string;
}

const Chatbot: FC<ChatbotProps> = ({ isOpen, onClose }) => {
  // State
  const [inputValue, setInputValue] = useState<string>("");
  const [isProcessing, setIsProcessing] = useState<boolean>(false);
  const [connectionStatus, setConnectionStatus] =
    useState<ConnectionStatus>("disconnected");
  const [isTyping, setIsTyping] = useState<boolean>(false);
  const [currentSessionId, setCurrentSessionId] = useState<string | null>(null);
  const [socket, setSocket] = useState<Socket | null>(null);
  const [showChatbot, setShowChatbot] = useState<boolean>(false);
  const [reconnectAttempts, setReconnectAttempts] = useState<number>(0);
  const maxReconnectAttempts = 5;

  // Sessions related state
  const [sessions, setSessions] = useState<ChatSession[]>([]);
  const [isLoadingSessions, setIsLoadingSessions] = useState<boolean>(false);
  const [showSessionSelect, setShowSessionSelect] = useState<boolean>(true);

  // Config
  const apiBaseUrl = import.meta.env.VITE_BASE_URL;
  const messagesEndRef = useRef<HTMLDivElement>(null);
  const connectionTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(
    null
  );

  // Custom hooks
  const {
    messages,
    addMessage,
    addSystemMessage,
    updateMessage,
    setMessages,
  } = useMessages();
  const { setupSocketHandlers } = useSocketHandlers({
    socket,
    setStatus: (status: string) => {
      console.log("📊 Status update:", status);
      // Map status string to connection status
      if (
        status.includes("متصل شد") ||
        status.includes("آماده") ||
        status.includes("متصل و آماده")
      ) {
        setConnectionStatus("connected");
      } else if (status.includes("در حال")) {
        setConnectionStatus("connecting");
      } else if (status.includes("خطا")) {
        setConnectionStatus("error");
      } else if (status.includes("قطع")) {
        setConnectionStatus("disconnected");
      }
    },
    setIsTyping,
    setIsProcessing,
    addMessage,
    updateMessage,
    addSystemMessage,
    setCurrentSessionId,
    isProcessing,
  });

  // Debug connection status changes
  useEffect(() => {
    console.log("🔄 Connection status changed:", {
      connectionStatus,
      socketConnected: socket?.connected,
      currentSessionId,
      isProcessing,
    });
  }, [connectionStatus, socket?.connected, currentSessionId, isProcessing]);

  // Monitor socket connection and session state
  useEffect(() => {
    if (socket?.connected && currentSessionId) {
      console.log(
        "🔗 Socket connected and session ready - setting status to connected"
      );
      setConnectionStatus("connected");
    }
  }, [socket?.connected, currentSessionId]);

  // Update button state when processing state changes
  useEffect(() => {
    updateButtonState();
  }, [isProcessing, connectionStatus, inputValue]);

  // Initialize component
  const init = () => {
    console.log("✅ DZone ChatBot initialized!");
  };

  // Run initialization once on mount
  useEffect(() => {
    init();
  }, []);

  // Animation effect for opening/closing
  useEffect(() => {
    if (isOpen) {
      // Small delay to trigger animation
      setTimeout(() => setShowChatbot(true), 50);
    } else {
      setShowChatbot(false);
    }
  }, [isOpen]);

  // Connect to socket and fetch sessions when component mounts
  useEffect(() => {
    if (isOpen) {
      connectSocket();
      fetchSessions();
    }

    // Cleanup on unmount or when closed
    return () => {
      disconnectSocket();
      if (connectionTimeoutRef.current) {
        clearTimeout(connectionTimeoutRef.current);
      }
    };
  }, [isOpen]);

  // Handle reconnection attempts
  useEffect(() => {
    if (
      connectionStatus === "error" &&
      reconnectAttempts < maxReconnectAttempts
    ) {
      const reconnectTimer = setTimeout(() => {
        attemptReconnect();
      }, 2000 * (reconnectAttempts + 1)); // Exponential backoff

      return () => clearTimeout(reconnectTimer);
    }
  }, [connectionStatus, reconnectAttempts]);

  // Scroll to bottom when messages change
  useEffect(() => {
    scrollToBottom();
  }, [messages]);

  // Set up socket handlers when socket changes
  useEffect(() => {
    let cleanup: (() => void) | undefined;

    if (socket) {
      console.log("🔄 Setting up socket handlers");
      cleanup = setupSocketHandlers();
    }

    return () => {
      if (cleanup) {
        console.log("🔄 Cleaning up socket handlers");
        cleanup();
      }
    };
  }, [socket]); // Only depend on socket, not setupSocketHandlers

  // Fetch user's previous chat sessions
  const fetchSessions = async () => {
    try {
      setIsLoadingSessions(true);
      const token = await getToken();
      const response = await axios.get(`${apiBaseUrl}/chatbot/sessions`, {
        headers: { Authorization: `Bearer ${token}` }
      });

      // Extract sessions from response.data.data as the API returns { statusCode, success, data: [...sessions] }
      const sessionsData = response.data?.data || [];
      setSessions(sessionsData);
      console.log("📝 Fetched sessions:", sessionsData);
    } catch (error) {
      console.error("Error fetching sessions:", error);
      addSystemMessage("خطا در دریافت جلسات قبلی", "error");
    } finally {
      setIsLoadingSessions(false);
    }
  };

  // Join an existing chat session
  const joinChat = (sessionId: string) => {
    if (!socket || !socket.connected) {
      addSystemMessage("اتصال Socket.IO برقرار نیست", "error");
      return;
    }

    // Get user ID from localStorage or use a default
    const userId =
      localStorage.getItem(import.meta.env.VITE_USER_ID_KEY || "user_id") ||
      localStorage.getItem("userId") ||
      "anonymous_user";

    console.log(`🔄 Joining chat session: ${sessionId}`);
    socket.emit(SOCKET_EVENTS.JOIN_CHAT, {
      sessionId: sessionId,
      userId: userId,
    });
  };

  // Load a specific session with its messages
  const loadSession = async (sessionId: string) => {
    try {
      setIsProcessing(true);
      const token = await getToken();

      // First ensure we have a socket connection
      if (!socket || !socket.connected) {
        console.log("Socket not connected, connecting first...");
        await connectSocketPromise(token);
      }

      const response = await axios.get(`${apiBaseUrl}/chatbot/sessions/${sessionId}`, {
        headers: { Authorization: `Bearer ${token}` }
      });

      // Extract session data from response.data.data
      const sessionData = response.data?.data || {};

      // Set current session ID
      setCurrentSessionId(sessionId);

      // Convert API messages to our message format and load them
      if (sessionData && sessionData.messages) {
        const formattedMessages = sessionData.messages.map((msg: any) => ({
          id: msg.id || Date.now().toString() + Math.random().toString(),
          text: msg.content || msg.text || "",
          isUser: msg.type === "user",
          isSystem: msg.type === "system",
          timestamp: new Date(msg.createdAt || msg.timestamp || Date.now()),
          metadata: msg.metadata || {}
        }));

        setMessages(formattedMessages);
      }

      // Join the chat session
      if (socket && socket.connected) {
        joinChat(sessionId);
      } else {
        console.error("Still couldn't connect socket after retrying");
        addSystemMessage("خطا در اتصال به سرور چت", "error");
      }

      // Switch to chat view
      setShowSessionSelect(false);
    } catch (error) {
      console.error("Error loading session:", error);
      addSystemMessage("خطا در بارگذاری جلسه", "error");
    } finally {
      setIsProcessing(false);
    }
  };

  // Promise-based socket connection
  const connectSocketPromise = (token: string | undefined): Promise<Socket> => {
    return new Promise((resolve, reject) => {
      try {
        setConnectionStatus("connecting");

        if (!apiBaseUrl) {
          console.error("API base URL not defined");
          setConnectionStatus("error");
          reject(new Error("API base URL not defined"));
          return;
        }

        if (!token) {
          console.error("No authentication token available");
          setConnectionStatus("error");
          reject(new Error("No authentication token available"));
          return;
        }

        console.log("🔄 Connecting to Socket.IO...");
        const newSocket = io(`${apiBaseUrl}/chat`, {
          auth: { token }
        });

        // Set up connection timeout
        const timeout = setTimeout(() => {
          if (newSocket.connected) {
            clearTimeout(timeout);
            return;
          }

          console.log("❌ Connection timeout");
          setConnectionStatus("error");
          reject(new Error("Connection timeout"));
        }, 10000);

        // Handle successful connection
        newSocket.on("connect", () => {
          console.log("✅ Socket connected successfully");
          setConnectionStatus("connected");
          setSocket(newSocket);
          clearTimeout(timeout);
          resolve(newSocket);
        });

        // Handle connection error
        newSocket.on("connect_error", (err) => {
          console.error("Socket connection error:", err);
          setConnectionStatus("error");
          clearTimeout(timeout);
          reject(err);
        });
      } catch (error) {
        console.error("Socket connection promise error:", error);
        setConnectionStatus("error");
        reject(error);
      }
    });
  };

  // Create a new chat session
  const handleCreateNewSession = async () => {
    try {
      setIsProcessing(true);
      setShowSessionSelect(false);
      setCurrentSessionId(null);
      setMessages([]);

      // Ensure socket is connected
      if (!socket || !socket.connected) {
        const token = await getToken();
        await connectSocketPromise(token);
      }

      // Create a new session
      if (socket && socket.connected) {
        createSession(socket);
      } else {
        console.error("Failed to connect socket for new session");
        addSystemMessage("خطا در اتصال به سرور چت", "error");
      }
    } catch (error) {
      console.error("Error creating new session:", error);
      addSystemMessage("خطا در ایجاد جلسه جدید", "error");
    } finally {
      setIsProcessing(false);
    }
  };

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

  const connectSocket = async () => {
    try {
      const token = await getToken();
      await connectSocketPromise(token);
      setReconnectAttempts(0);
    } catch (error) {
      console.error("Socket connection error:", error);
      setConnectionStatus("error");
      attemptReconnect();
    }
  };

  const attemptReconnect = () => {
    if (reconnectAttempts < maxReconnectAttempts) {
      const newAttempts = reconnectAttempts + 1;
      setReconnectAttempts(newAttempts);
      console.log(
        `🔄 Reconnecting... Attempt ${newAttempts}/${maxReconnectAttempts}`
      );

      setTimeout(() => {
        connectSocket();
      }, 2000 * newAttempts); // Exponential backoff
    } else {
      console.log("❌ Max reconnection attempts reached");
      addSystemMessage("اتصال قطع شد. لطفاً صفحه را تازه کنید", "error");
    }
  };

  const disconnectSocket = () => {
    if (socket) {
      socket.disconnect();
      setSocket(null);
      setConnectionStatus("disconnected");
    }
  };

  const createSession = (socketInstance: Socket | null = socket) => {
    if (!socketInstance || !socketInstance.connected) {
      console.log("❌ Socket not connected for session creation");
      return;
    }

    if (currentSessionId) {
      console.log("🚫 Session already exists:", currentSessionId);
      addSystemMessage("جلسه از قبل وجود دارد", "info");
      return;
    }

    console.log("🔄 Creating new session via Socket.IO...");
    socketInstance.emit(SOCKET_EVENTS.CREATE_SESSION, {
      title: `چت ${new Date().toLocaleDateString("fa-IR")}`,
    });
  };

  const handleSendMessage = () => {
    const message = inputValue.trim();

    if (!message || isProcessing) {
      console.log("❌ Cannot send:", {
        message: !!message,
        processing: isProcessing,
      });
      return;
    }

    // Check Socket.IO connection
    if (!socket || !socket.connected) {
      addSystemMessage("اتصال Socket.IO برقرار نیست", "error");
      return;
    }

    // Auto-create session if needed
    if (!currentSessionId) {
      console.log("📝 No session, creating one...");
      createSession();
      addSystemMessage("لطفاً منتظر ایجاد جلسه باشید", "info");
      return;
    }

    try {
      // Disable during processing
      setIsProcessing(true);
      updateButtonState();

      // Add user message to UI
      addMessage({
        text: message,
        isUser: true,
      });

      // Clear input immediately to prevent accidental resend
      setInputValue("");
      autoResizeTextarea({
        target: { value: "", style: { height: "auto" } },
      } as React.ChangeEvent<HTMLTextAreaElement>);

      // Get user ID from localStorage or use a default
      const userId =
        localStorage.getItem(import.meta.env.VITE_USER_ID_KEY || "user_id") ||
        localStorage.getItem("userId") ||
        "anonymous_user";

      // Send message via Socket.IO
      console.log("📤 Sending message via Socket.IO");
      socket.emit(SOCKET_EVENTS.SEND_MESSAGE, {
        sessionId: currentSessionId,
        content: message,
        userId: userId,
      });
    } catch (error) {
      console.error("Send message error:", error);
      addSystemMessage(`خطا در ارسال پیام`, "error");
      setIsProcessing(false);
      updateButtonState();
    }
  };

  const handleKeyPress = (e: React.KeyboardEvent) => {
    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault();
      handleSendMessage();
    }
  };

  const autoResizeTextarea = (
    e:
      | React.ChangeEvent<HTMLTextAreaElement>
      | { target: { value: string; style?: { height: string } } }
  ): void => {
    const value = e.target.value;
    setInputValue(value);

    // Handle the case when this is called programmatically without a real DOM element
    if ("style" in e.target) {
      const textarea = e.target as HTMLTextAreaElement;
      textarea.style.height = "auto";
      textarea.style.height = Math.min(textarea.scrollHeight, 150) + "px";
    }

    updateButtonState();
  };

  const updateButtonState = () => {
    const hasText = inputValue.trim().length > 0;
    const canSend =
      hasText && !isProcessing && connectionStatus === "connected";

    console.log("🔄 Button state updated:", {
      hasText,
      isProcessing,
      connectionStatus,
      currentSessionId,
      canSend,
    });
  };

  // Format date for session list
  const formatDate = (dateString: string) => {
    const date = new Date(dateString);
    return date.toLocaleDateString("fa-IR", {
      year: "numeric",
      month: "long",
      day: "numeric",
    });
  };

  // Handle return to sessions list
  const handleReturnToSessions = () => {
    setShowSessionSelect(true);
  };

  if (!isOpen) return null;

  return (
    <div
      className={`fixed bottom-20 right-4 w-80 sm:w-96 bg-white rounded-xl shadow-xl flex flex-col z-50 border border-gray-200 transition-all duration-300 ease-in-out ${showChatbot
        ? "opacity-100 transform translate-y-0"
        : "opacity-0 transform translate-y-10"
        }`}
      style={{ height: "500px", direction: "rtl" }}
    >
      {/* Header */}
      <div className="bg-black text-white p-3.5 rounded-t-xl flex justify-between items-center shadow-sm">
        <div className="flex items-center">
          <div
            className={`w-3 h-3 rounded-full ml-2 ${connectionStatus === "connected"
              ? "bg-green-400 animate-pulse"
              : connectionStatus === "connecting"
                ? "bg-yellow-400 animate-pulse"
                : "bg-red-400"
              }`}
          ></div>
          {!showSessionSelect && (
            <button
              onClick={handleReturnToSessions}
              className="ml-2 p-1 focus:outline-none hover:bg-gray-700 rounded-full transition-colors"
              title="برگشت به لیست جلسات"
            >
              <ArrowRight size={18} />
            </button>
          )}
          <h3 className="font-bold text-base">چت بات داناک</h3>
        </div>
        <button
          onClick={onClose}
          className="focus:outline-none hover:bg-gray-700 p-1 rounded-full transition-colors"
          aria-label="بستن چت"
        >
          <CloseCircle size={20} />
        </button>
      </div>

      {showSessionSelect ? (
        /* Sessions Selection Screen */
        <div className="flex-1 p-3.5 overflow-y-auto bg-gray-50">
          <div className="mb-4">
            <h3 className="text-lg font-bold text-gray-800 mb-2">جلسات قبلی شما</h3>
            <p className="text-sm text-gray-600">یک جلسه را انتخاب کنید یا جلسه جدیدی بسازید.</p>
          </div>

          {isLoadingSessions ? (
            <div className="flex justify-center items-center h-64">
              <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-gray-900"></div>
            </div>
          ) : (
            <>
              <button
                onClick={handleCreateNewSession}
                className="w-full bg-black text-white rounded-lg p-3 mb-4 flex items-center justify-center hover:bg-gray-800 transition-colors"
              >
                <Add size={20} className="ml-2" />
                <span>شروع جلسه جدید</span>
              </button>

              {sessions.length === 0 ? (
                <div className="text-center text-gray-500 p-4">
                  هنوز هیچ جلسه‌ای ندارید
                </div>
              ) : (
                <div className="space-y-2">
                  {sessions.map((session) => (
                    <div
                      key={session.id}
                      onClick={() => loadSession(session.id)}
                      className="bg-white p-3 rounded-lg shadow-sm cursor-pointer hover:bg-gray-100 transition-colors"
                    >
                      <div className="font-medium">{session.title}</div>
                      <div className="text-xs text-gray-500 mt-1">
                        {formatDate(session.createdAt)}
                      </div>
                    </div>
                  ))}
                </div>
              )}
            </>
          )}
        </div>
      ) : (
        /* Chat UI */
        <>
          {/* Messages */}
          <div
            className="flex-1 p-3.5 overflow-y-auto bg-gray-50"
            style={{ height: "350px" }}
          >
            {messages?.map((message: Message) => {
              // Debug message content
              console.log(`Rendering message ${message.id}:`, {
                text:
                  message.text.substring(0, 30) +
                  (message.text.length > 30 ? "..." : ""),
                isUser: message.isUser,
                isSystem: message.isSystem,
                streaming: message.streaming,
              });

              return (
                <div
                  key={message.id}
                  className={`mb-3 flex ${message.isUser ? "justify-start" : "justify-end"
                    } animate-fade-in`}
                >
                  {message.isUser && (
                    <div className="w-7 h-7 rounded-full bg-black flex items-center justify-center ml-2 flex-shrink-0">
                      <span className="text-white text-xs"><User size={14} color="white" /></span>
                    </div>
                  )}
                  <div
                    className={`relative px-3.5 py-2.5 pb-4 rounded-lg max-w-[85%] ${message.isUser
                      ? "bg-black text-white rounded-tr-none shadow-sm animate-slide-right"
                      : message.isSystem
                        ? message.metadata?.type === "error"
                          ? "bg-red-100 text-red-800 rounded-tl-none"
                          : message.metadata?.type === "success"
                            ? "bg-green-100 text-green-800 rounded-tl-none"
                            : "bg-yellow-100 text-yellow-800 rounded-tl-none"
                        : message.metadata && "confidence" in message.metadata
                          ? message.metadata.confidence === 1
                            ? "bg-green-100 text-green-800 rounded-tl-none"
                            : message.metadata.confidence === 0
                              ? "bg-red-100 text-red-800 rounded-tl-none"
                              : "bg-yellow-100 text-yellow-800 rounded-tl-none"
                          : "bg-white text-gray-800 rounded-tl-none shadow-sm animate-slide-left"
                      } ${message.streaming
                        ? "border-r-4 border-gray-400 streaming-message animate-pulse"
                        : ""
                      }`}
                  >
                    <div
                      id={`message-${message.id}`}
                      className={`text-sm leading-6 font-light whitespace-pre-line break-words text-right mb-2 ${message.streaming ? "streaming-content" : ""
                        }`}
                      dangerouslySetInnerHTML={{ __html: formatText(message.text) }}
                    />
                    <div
                      className={`text-[8px] opacity-70 absolute bottom-1 ${message.isUser
                        ? "left-2.5 text-left"
                        : "right-2.5 text-right"
                        }`}
                    >
                      {message.timestamp.toLocaleTimeString("fa-IR", {
                        hour: "2-digit",
                        minute: "2-digit",
                      })}
                    </div>
                    {message.metadata?.confidence !== undefined &&
                      message.metadata.confidence !== 0 &&
                      message.metadata.confidence !== 0.5 &&
                      message.metadata.confidence !== 1 && (
                        <div className="text-[9px] mt-0.5 text-right">
                          اعتماد: {Math.round(message.metadata.confidence * 100)}%
                        </div>
                      )}
                  </div>
                  {!message.isUser && !message.isSystem && (
                    <div className="w-7 h-7 rounded-full bg-gray-200 flex items-center justify-center mr-2 flex-shrink-0">
                      <span className="text-gray-600 text-xs">🤖</span>
                    </div>
                  )}
                </div>
              );
            })}
            {/* Typing indicator - only show when no streaming messages exist */}
            {isTyping && !messages.some((msg) => msg.streaming) && (
              <div className="flex justify-end mb-3 animate-fade-in">
                <div className="bg-white text-gray-800 px-3.5 py-2 rounded-lg rounded-tl-none shadow-sm">
                  <div className="typing-indicator">
                    <span>در حال پاسخ...</span>
                    <span></span>
                    <span></span>
                  </div>
                </div>
                <div className="w-7 h-7 rounded-full bg-gray-200 flex items-center justify-center mr-2 flex-shrink-0">
                  <span className="text-gray-600 text-xs">🤖</span>
                </div>
              </div>
            )}
            <div ref={messagesEndRef} />
          </div>

          {/* Input */}
          <div className="border-t border-gray-200 p-3 bg-white rounded-b-xl">
            <div className="flex items-center bg-gray-50 rounded-full pl-1 pr-3 overflow-hidden shadow-inner">
              <textarea
                value={inputValue}
                onChange={autoResizeTextarea}
                onKeyPress={handleKeyPress}
                placeholder="پیام خود را بنویسید..."
                disabled={isProcessing || connectionStatus !== "connected"}
                className="flex-1 bg-transparent border-none px-2 py-2.5 text-sm focus:outline-none resize-none min-h-[40px] font-light"
                style={{ maxHeight: "80px" }}
              />

              <button
                onClick={handleSendMessage}
                disabled={
                  inputValue.trim() === "" ||
                  isProcessing ||
                  connectionStatus !== "connected"
                }
                className={`ml-2 ${inputValue.trim() === "" ||
                  isProcessing ||
                  connectionStatus !== "connected"
                  ? "bg-gray-300"
                  : "bg-gray-800 hover:bg-gray-900"
                  } text-white rounded-full w-9 h-9 flex items-center justify-center focus:outline-none transition-colors flex-shrink-0`}
              >
                <Send
                  size={18}
                  className={`transform rotate-180 ${inputValue.trim() !== "" &&
                    !isProcessing &&
                    connectionStatus === "connected"
                    ? "animate-pulse"
                    : ""
                    }`}
                />
              </button>
            </div>
          </div>
        </>
      )}
    </div>
  );
};

export default Chatbot;