/**
 * useChatbot Hook
 * 
 * Hook for managing chatbot conversations, messages, and chat functionality.
 */

import { useState, useEffect, useCallback, useRef } from 'react';
import { useApiRequest } from './useApi';
import { 
  getChatbotThreadsApi, 
  getChatbotThreadApi, 
  startChatbotStreamApi, 
  stopChatbotApi,
  deleteChatbotWorkflowApi,
  type ChatbotWorkflow,
  type ChatDataItem,
  type StartChatbotRequest
} from '../api/chatbotApi';
import { Message, getConversationId } from '../components/UiComponents/Messages/MessagesTypes';
import { useInstanceId } from './useCurrentInstance';

export interface ChatbotHookReturn {
  // Threads/Conversations
  threads: ChatbotWorkflow[];
  selectedThreadId: string | null;
  loadingThreads: boolean;
  error: string | null;
  
  // Messages
  messages: Message[];
  loadingMessages: boolean;
  
  // Current workflow state
  currentWorkflowId: string | null;
  isStreaming: boolean;
  streamingStatus: string | null; // Current streaming status message
  
  // Actions
  selectThread: (workflowId: string) => Promise<void>;
  createNewThread: () => void;
  sendMessage: (input: string, files?: Array<{ id: string; name: string }>) => Promise<void>;
  stopStreaming: () => Promise<void>;
  deleteThread: (workflowId: string) => Promise<void>;
  refreshThreads: () => Promise<void>;
  
  // Input form state
  inputValue: string;
  setInputValue: (value: string) => void;
}

/**
 * Main chatbot hook
 */
export function useChatbot(): ChatbotHookReturn {
  const { request } = useApiRequest();
  const instanceId = useInstanceId();
  
  // Threads state
  const [threads, setThreads] = useState<ChatbotWorkflow[]>([]);
  const [selectedThreadId, setSelectedThreadId] = useState<string | null>(null);
  const [loadingThreads, setLoadingThreads] = useState(false);
  
  // Messages state
  const [messages, setMessages] = useState<Message[]>([]);
  const [loadingMessages, setLoadingMessages] = useState(false);
  
  // Current workflow state
  const [currentWorkflowId, setCurrentWorkflowId] = useState<string | null>(null);
  const [isStreaming, setIsStreaming] = useState(false);
  const [streamingStatus, setStreamingStatus] = useState<string | null>(null);
  
  // Error state
  const [error, setError] = useState<string | null>(null);
  
  // Input state
  const [inputValue, setInputValue] = useState('');
  
  // Ref to track if component is mounted
  const isMountedRef = useRef(true);
  
  useEffect(() => {
    isMountedRef.current = true;
    return () => {
      isMountedRef.current = false;
    };
  }, []);
  
  // Load threads
  const refreshThreads = useCallback(async () => {
    if (!instanceId) return;
    
    setLoadingThreads(true);
    setError(null);
    try {
      const result = await getChatbotThreadsApi(request, instanceId);
      if (isMountedRef.current) {
        setThreads(result.items || []);
      }
    } catch (err: any) {
      console.error('Error loading threads:', err);
      if (isMountedRef.current) {
        setError(err.message || 'Fehler beim Laden der Konversationen');
      }
    } finally {
      if (isMountedRef.current) {
        setLoadingThreads(false);
      }
    }
  }, [request, instanceId]);
  
  // Load messages for a thread
  const loadThreadMessages = useCallback(async (workflowId: string) => {
    if (!instanceId) return;
    
    setLoadingMessages(true);
    setError(null);
    try {
      const result = await getChatbotThreadApi(request, instanceId, workflowId);
      if (isMountedRef.current) {
        // Extract messages from chatData items
        const messageItems = (result.chatData?.items || [])
          .filter((item: ChatDataItem) => item.type === 'message')
          .map((item: ChatDataItem) => item.item as Message);
        
        setMessages(messageItems);
        setCurrentWorkflowId(workflowId);
      }
    } catch (err: any) {
      console.error('Error loading thread messages:', err);
      if (isMountedRef.current) {
        setError(err.message || 'Fehler beim Laden der Nachrichten');
        setMessages([]);
      }
    } finally {
      if (isMountedRef.current) {
        setLoadingMessages(false);
      }
    }
  }, [request, instanceId]);
  
  // Select a thread
  const selectThread = useCallback(async (workflowId: string) => {
    setSelectedThreadId(workflowId);
    await loadThreadMessages(workflowId);
  }, [loadThreadMessages]);
  
  // Create new thread
  const createNewThread = useCallback(() => {
    setSelectedThreadId(null);
    setMessages([]);
    setCurrentWorkflowId(null);
    setInputValue('');
  }, []);
  
  // Send message
  const sendMessage = useCallback(async (
    input: string, 
    files?: Array<{ id: string; name: string }>
  ) => {
    if (!input.trim() || isStreaming || !instanceId) return;
    
    setError(null);
    setIsStreaming(true);
    setStreamingStatus(null); // Reset status
    
    // Store the input message content to track duplicates
    const inputMessageContent = input.trim();
    
    // Add user message immediately for better UX
    const tempUserMessageId = `temp-user-${Date.now()}`;
    const userMessage: Message = {
      id: tempUserMessageId,
      workflowId: currentWorkflowId || undefined,
      conversationId: currentWorkflowId || undefined,
      role: 'user',
      message: inputMessageContent,
      publishedAt: Date.now()
    };
    
    setMessages(prev => [...prev, userMessage]);
    setInputValue('');
    
    try {
      const requestBody: StartChatbotRequest = {
        prompt: input,
        workflowId: currentWorkflowId || undefined,
        listFileId: files?.map(f => f.id),
        userLanguage: navigator.language || 'de'
      };
      
      let newWorkflowId: string | null = null;
      
      await startChatbotStreamApi(
        instanceId,
        requestBody,
        (item: ChatDataItem) => {
          if (!isMountedRef.current) return;
          
          // Handle stopped event
          if (item.type === 'stopped') {
            console.log('Received stopped event from backend');
            setIsStreaming(false);
            setStreamingStatus(null);
            return;
          }
          
          // Handle status event (streaming progress updates)
          if (item.type === 'status') {
            const statusLabel = item.label || (item.item as any)?.label || '';
            console.log('Received status update:', statusLabel);
            setStreamingStatus(statusLabel);
            return;
          }
          
          // Handle chunk events (ChatGPT-like token-by-token streaming)
          if (item.type === 'chunk' && item.content) {
            setMessages(prev => {
              const last = prev[prev.length - 1];
              if (last?.role === 'assistant') {
                return prev.map(m =>
                  m.id === last!.id ? { ...m, message: (m.message || '') + item.content } : m
                );
              }
              return [...prev, {
                id: `streaming-${currentWorkflowId || 'new'}-${Date.now()}`,
                workflowId: currentWorkflowId || undefined,
                conversationId: currentWorkflowId || undefined,
                role: 'assistant' as const,
                message: item.content,
                publishedAt: Date.now()
              }];
            });
            return;
          }
          
          // Handle workflow update (includes name updates from background task)
          if (item.type === 'stat' && item.item?.id) {
            newWorkflowId = item.item.id;
            setCurrentWorkflowId(item.item.id);
            if (!selectedThreadId) {
              setSelectedThreadId(item.item.id);
            }
            // Check if workflow status is stopped
            if (item.item.status === 'stopped') {
              console.log('Workflow status is stopped');
              setIsStreaming(false);
            }
            // Refresh threads when workflow data arrives (e.g. name update from background)
            if (item.item?.name) {
              refreshThreads();
            }
          }
          
          // Handle messages
          if (item.type === 'message' && item.item) {
            const message = item.item as Message;

            // Extract conversation/workflow ID from message (supports workflowId and conversationId)
            const extractedWorkflowId = getConversationId(message);
            if (extractedWorkflowId) {
              // Update local variable and state if not already set
              if (!newWorkflowId) {
                newWorkflowId = extractedWorkflowId;
                console.log('Extracting workflowId from message:', extractedWorkflowId);
              }
              // Always update state to ensure we have the latest workflowId
              setCurrentWorkflowId(prev => {
                if (!prev) {
                  console.log('Setting currentWorkflowId from message:', extractedWorkflowId);
                  return extractedWorkflowId;
                }
                return prev;
              });
              if (!selectedThreadId) {
                setSelectedThreadId(extractedWorkflowId);
              }
            }
            
            setMessages(prev => {
              // Check if message already exists by ID
              if (prev.some(m => m.id === message.id)) {
                return prev;
              }
              
              // Backend sends the "first" message with the transformed/normalized user prompt
              // Replace the temporary optimistic message with it
              if (message.status === 'first') {
                return prev.map(m => 
                  m.id === tempUserMessageId ? message : m
                );
              }
              
              // Final assistant message: replace streaming placeholder if we have one
              if (message.role === 'assistant') {
                const streamingIdx = prev.findIndex(m => m.id?.startsWith('streaming-'));
                if (streamingIdx >= 0) {
                  const before = prev.slice(0, streamingIdx);
                  const after = prev.slice(streamingIdx + 1);
                  return [...before, message, ...after];
                }
              }
              
              // For other messages, check for duplicates by role and content (more lenient check)
              const isDuplicate = prev.some(m => {
                // Exact ID match
                if (m.id === message.id) return true;
                // For same role and content, check if it's a duplicate
                if (m.role === message.role && m.message === message.message) {
                  // If it's a user message, it's definitely a duplicate
                  if (message.role === 'user') return true;
                  // For assistant messages, check if timestamps are very close (within 1 second)
                  if (m.publishedAt && message.publishedAt) {
                    return Math.abs(m.publishedAt - message.publishedAt) < 1000;
                  }
                }
                return false;
              });
              
              if (isDuplicate) return prev;
              return [...prev, message];
            });
          }
        },
        (err: Error) => {
          console.error('Stream error:', err);
          if (isMountedRef.current) {
            setError(err.message || 'Fehler beim Senden der Nachricht');
            setIsStreaming(false);
          }
        },
        () => {
          if (isMountedRef.current) {
            setIsStreaming(false);
            setStreamingStatus(null); // Clear status on completion
            // Refresh threads to get updated list
            refreshThreads();
          }
        }
      );
      
      // Refresh threads after completion
      if (newWorkflowId) {
        await refreshThreads();
      }
    } catch (err: any) {
      console.error('Error sending message:', err);
      if (isMountedRef.current) {
        setError(err.message || 'Fehler beim Senden der Nachricht');
        setIsStreaming(false);
      }
    }
  }, [currentWorkflowId, selectedThreadId, isStreaming, instanceId, refreshThreads]);
  
  // Stop streaming
  const stopStreaming = useCallback(async () => {
    if (!instanceId) {
      console.warn('Cannot stop: missing instanceId', { instanceId });
      return;
    }
    
    if (!isStreaming) {
      console.warn('Cannot stop: not currently streaming');
      return;
    }
    
    // Immediately reset UI state for instant feedback
    setIsStreaming(false);
    console.log('UI reset immediately after stop button click');
    
    // Try to get workflowId from currentWorkflowId, or from the latest message
    let workflowIdToStop = currentWorkflowId;
    if (!workflowIdToStop && messages.length > 0) {
      // Try to extract workflowId from the latest message (supports workflowId and conversationId)
      const latestMessage = messages[messages.length - 1];
      workflowIdToStop = getConversationId(latestMessage) ?? null;
      if (workflowIdToStop) {
        console.log('Extracted workflowId from latest message:', workflowIdToStop);
      }
    }
    
    if (!workflowIdToStop) {
      console.warn('Cannot stop: missing workflowId, but UI already reset', { 
        currentWorkflowId, 
        messagesCount: messages.length,
        latestMessage: messages.length > 0 ? messages[messages.length - 1] : null
      });
      // UI already reset above, just return
      return;
    }
    
    // Send stop request to backend (fire and forget - UI already reset)
    try {
      console.log('Sending stop request to backend for workflow:', workflowIdToStop);
      // Don't await - let it run in background, UI is already reset
      stopChatbotApi(request, instanceId, workflowIdToStop).catch((err: any) => {
        console.error('Error stopping stream on backend (non-blocking):', err);
        // Optionally show a non-intrusive error notification
        if (isMountedRef.current) {
          // Don't reset isStreaming again as it's already false
          // Just log the error
          console.warn('Backend stop request failed, but UI was already reset');
        }
      });
    } catch (err: any) {
      console.error('Error initiating stop request:', err);
      // UI already reset, so just log the error
    }
  }, [currentWorkflowId, isStreaming, instanceId, request, messages]);
  
  // Delete thread
  const deleteThread = useCallback(async (workflowId: string) => {
    if (!instanceId) return;
    
    // Optimistic UI update - remove thread immediately
    const previousThreads = threads;
    setThreads(prev => prev.filter(t => t.id !== workflowId));
    
    // If deleted thread was selected, clear selection immediately
    if (selectedThreadId === workflowId) {
      createNewThread();
    }
    
    try {
      await deleteChatbotWorkflowApi(request, instanceId, workflowId);
      
      // Refresh threads list to sync with server
      await refreshThreads();
    } catch (err: any) {
      console.error('Error deleting thread:', err);
      // Restore threads on error
      setThreads(previousThreads);
      setError(err.message || 'Fehler beim Löschen der Konversation');
    }
  }, [request, instanceId, selectedThreadId, threads, createNewThread, refreshThreads]);
  
  // Initial load
  useEffect(() => {
    if (instanceId) {
      refreshThreads();
    }
  }, [instanceId, refreshThreads]);
  
  return {
    threads,
    selectedThreadId,
    loadingThreads,
    error,
    messages,
    loadingMessages,
    currentWorkflowId,
    isStreaming,
    streamingStatus,
    selectThread,
    createNewThread,
    sendMessage,
    stopStreaming,
    deleteThread,
    refreshThreads,
    inputValue,
    setInputValue
  };
}

/**
 * Hook factory for use in GenericPageData inputFormConfig
 */
export function createChatbotHook() {
  return () => {
    const chatbot = useChatbot();
    
    return {
      messages: chatbot.messages,
      loading: chatbot.loadingMessages || chatbot.isStreaming,
      error: chatbot.error,
      data: [],
      inputValue: chatbot.inputValue,
      onInputChange: chatbot.setInputValue,
      handleSubmit: async () => {
        await chatbot.sendMessage(chatbot.inputValue);
      },
      isSubmitting: chatbot.isStreaming,
      stopAction: chatbot.stopStreaming,
      canStop: chatbot.isStreaming
    };
  };
}
