"use client"

import { useState, useEffect, useCallback, useRef } from "react"
import { toast } from "sonner"
import { History as HistoryIcon } from "lucide-react"
import {
  ChatSidebar
} from "./chat/ChatSidebar"
import { ChatHeader } from "./chat/ChatHeader"
import { AmaniMessageList } from "./chat/AmaniMessageList"
import { ChatInput } from "./chat/ChatInput"
import type {
  Message,
  ChatSession,
  StreamMetadata,
  SharePlatform,
  ShareFormatResponse,
  ShareSheetState
} from "./chat/types"

// Extend Window interface for OAuth callback
declare global {
  interface Window {
    handleOAuthCallback?: (platform: SharePlatform, code: string, state: string) => Promise<boolean>
  }
}

export function Chat() {
  const [messages, setMessages] = useState<Message[]>([])
  const [input, setInput] = useState("")
  const [isLoading, setIsLoading] = useState(false)
  const [currentSessionId, setCurrentSessionId] = useState<string | null>(null)
  const [useHybrid, setUseHybrid] = useState(false)
  const [chatHistory, setChatHistory] = useState<ChatSession[]>([])
  const [showHistory, setShowHistory] = useState(false)
  const [showSources, setShowSources] = useState(false)
  const [isResearchMode, setIsResearchMode] = useState(false)
  const [researchResults, setResearchResults] = useState<Record<string, unknown>>({})
  const [shareSheet, setShareSheet] = useState<ShareSheetState | null>(null)
  const [shareCache, setShareCache] = useState<
    Record<string, Partial<Record<SharePlatform, ShareFormatResponse>>>
  >({})
  const [autocompleteSuggestions, setAutocompleteSuggestions] = useState<string[]>([])
  const [showAutocomplete, setShowAutocomplete] = useState(false)
  const [selectedFiles, setSelectedFiles] = useState<File[]>([])
  const [uploadingFiles, setUploadingFiles] = useState(false)
  const [editingMessageId, setEditingMessageId] = useState<string | null>(null)
  const [editingContent, setEditingContent] = useState("")
  const [regeneratingMessageId, setRegeneratingMessageId] = useState<string | null>(null)
  const [isCreatingSession, setIsCreatingSession] = useState(false)
  const [platformTokens, setPlatformTokens] = useState<Record<SharePlatform, string | null>>({
    twitter: null,
    linkedin: null,
    facebook: null,
    whatsapp: null,
    telegram: null,
    email: null,
    threads: null,
    bluesky: null,
    tiktok: null
  })
  const autocompleteTimeoutRef = useRef<NodeJS.Timeout | null>(null)
  const messagesContainerRef = useRef<HTMLDivElement | null>(null)
  const messagesEndRef = useRef<HTMLDivElement | null>(null)

  const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"
  const ENABLE_AUTOCOMPLETE = process.env.NEXT_PUBLIC_ENABLE_AUTOCOMPLETE !== "false"

  // Helper function to get auth headers
  const getAuthHeaders = useCallback((): Record<string, string> => {
    const token = localStorage.getItem("session_token")
    return token ? { "X-Session-Token": token } : {}
  }, [])

  // Token management functions
  const getStoredToken = useCallback((platform: SharePlatform): string | null => {
    try {
      const tokens = JSON.parse(localStorage.getItem("platform_tokens") || "{}")
      return tokens[platform] || null
    } catch {
      return null
    }
  }, [])

  const storeToken = useCallback((platform: SharePlatform, token: string) => {
    try {
      const tokens = JSON.parse(localStorage.getItem("platform_tokens") || "{}")
      tokens[platform] = token
      localStorage.setItem("platform_tokens", JSON.stringify(tokens))
      setPlatformTokens(prev => ({ ...prev, [platform]: token }))
    } catch (error) {
      console.error("Failed to store token:", error)
    }
  }, [])

  const clearToken = useCallback((platform: SharePlatform) => {
    try {
      const tokens = JSON.parse(localStorage.getItem("platform_tokens") || "{}")
      delete tokens[platform]
      localStorage.setItem("platform_tokens", JSON.stringify(tokens))
      setPlatformTokens(prev => ({ ...prev, [platform]: null }))
    } catch (error) {
      console.error("Failed to clear token:", error)
    }
  }, [])

  const loadStoredTokens = useCallback(() => {
    try {
      const tokens = JSON.parse(localStorage.getItem("platform_tokens") || "{}")
      setPlatformTokens({
        twitter: tokens.twitter || null,
        linkedin: tokens.linkedin || null,
        facebook: tokens.facebook || null,
        whatsapp: null, // WhatsApp doesn't use OAuth tokens
        telegram: null, // Telegram doesn't use OAuth tokens
        email: null, // Email doesn't use OAuth tokens
        threads: tokens.threads || null,
        bluesky: tokens.bluesky || null,
        tiktok: null // TikTok might not support this flow yet or tokens.tiktok
      })
    } catch (error) {
      console.error("Failed to load stored tokens:", error)
    }
  }, [])

  const handleAuthCallback = useCallback(async (platform: SharePlatform, code: string, state: string) => {
    try {
      const response = await fetch(`${API_BASE_URL}/share/auth/callback`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ platform, code, state })
      })

      if (!response.ok) {
        throw new Error("Authentication callback failed")
      }

      const data = await response.json()
      if (data.access_token) {
        storeToken(platform, data.access_token)
        toast.success(`Successfully authenticated with ${platform}`)
        return true
      }
    } catch (error) {
      console.error("Auth callback failed:", error)
      toast.error(`Authentication failed for ${platform}`)
    }
    return false
  }, [API_BASE_URL, storeToken])

  // Load stored tokens on component mount
  useEffect(() => {
    loadStoredTokens()
    
    // Make handleAuthCallback available globally for OAuth redirects
    window.handleOAuthCallback = handleAuthCallback
    
    // Check for OAuth callback parameters in URL
    const urlParams = new URLSearchParams(window.location.search)
    const code = urlParams.get('code')
    const state = urlParams.get('state')
    const platform = urlParams.get('platform')
    
    if (code && state && platform) {
      // Handle OAuth callback
      handleAuthCallback(platform as SharePlatform, code, state).then(() => {
        // Clean up URL params
        window.history.replaceState({}, document.title, window.location.pathname)
      })
    }
    
    return () => {
      delete window.handleOAuthCallback
    }
  }, [loadStoredTokens, handleAuthCallback])

  // OAuth flow functions
  const initiateAuth = async (platform: SharePlatform) => {
    try {
      setShareSheet(prev => prev ? { ...prev, shareLinkLoading: true, shareError: null } : prev)

      const response = await fetch(`${API_BASE_URL}/share/auth`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ platform })
      })

      if (!response.ok) {
        const error = await response.json()
        throw new Error(error.detail || "Failed to initiate authentication")
      }

      const data = await response.json()

      if (data.status === "needs_auth" && data.auth_url) {
        // Open OAuth URL in popup or new window
        const authWindow = window.open(
          data.auth_url,
          `auth-${platform}`,
          "width=600,height=700,scrollbars=yes,resizable=yes"
        )

        if (authWindow) {
          // Listen for auth completion
          const checkClosed = setInterval(() => {
            if (authWindow.closed) {
              clearInterval(checkClosed)
              // Check if auth was successful by trying to get user info
              checkAuthStatus(platform)
            }
          }, 1000)
        }
      } else if (data.status === "authenticated") {
        // Already authenticated
        if (data.user_info?.access_token) {
          storeToken(platform, data.user_info.access_token)
        }
        toast.success(`Already authenticated with ${platform}`)
      }

      setShareSheet(prev => prev ? { ...prev, shareLinkLoading: false } : prev)
    } catch (error) {
      console.error("Failed to initiate auth:", error)
      setShareSheet(prev => prev ? {
        ...prev,
        shareLinkLoading: false,
        shareError: error instanceof Error ? error.message : "Authentication failed"
      } : prev)
    }
  }

  const checkAuthStatus = async (platform: SharePlatform) => {
    try {
      // Try to get user info to check if authenticated
      const response = await fetch(`${API_BASE_URL}/share/auth/status`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ platform })
      })

      if (response.ok) {
        const data = await response.json()
        if (data.status === "authenticated" && data.user_info?.access_token) {
          storeToken(platform, data.user_info.access_token)
          toast.success(`Successfully authenticated with ${platform}`)
          return true
        } else {
          // Clear token if not authenticated
          clearToken(platform)
        }
      } else {
        clearToken(platform)
      }
    } catch (error) {
      console.error("Failed to check auth status:", error)
      clearToken(platform)
    }
    return false
  }

  const scrollMessagesToBottom = useCallback(
    (behavior: ScrollBehavior = "smooth") => {
      requestAnimationFrame(() => {
        if (messagesContainerRef.current) {
          messagesContainerRef.current.scrollTo({
            top: messagesContainerRef.current.scrollHeight,
            behavior
          })
        }
        messagesEndRef.current?.scrollIntoView({ behavior, block: "end" })
      })
    },
    []
  )

  useEffect(() => {
    scrollMessagesToBottom(messages.length < 3 ? "instant" : "smooth")
  }, [messages, isLoading, scrollMessagesToBottom])

  const findPreviousUserPrompt = useCallback(
    (messageId: string) => {
      const index = messages.findIndex((msg) => msg.id === messageId)
      if (index === -1) return undefined
      for (let i = index - 1; i >= 0; i--) {
        if (messages[i].role === "user") {
          return messages[i].content
        }
      }
      return undefined
    },
    [messages]
  )

  const loadChatHistory = useCallback(async () => {
    try {
      const headers: Record<string, string> = {
        "Content-Type": "application/json",
        ...getAuthHeaders()
      }
      // Use cache API route instead of direct backend call
      const response = await fetch(`/api/cache/sessions`, {
        headers
      })
      if (response.ok) {
        const sessions = await response.json()
        setChatHistory(sessions)
        // Log cache hit/miss for debugging
        const cacheStatus = response.headers.get("X-Cache")
        if (cacheStatus) {
          console.log(`Sessions cache: ${cacheStatus}`)
        }
      }
    } catch (error) {
      console.error("Failed to load chat history:", error)
    }
  }, [getAuthHeaders])

  const createNewSession = useCallback(async (firstMessage?: string) => {
    let title = "New Chat"
    if (firstMessage) {
      const content = firstMessage.trim()
      if (content.length <= 50) {
        title = content
      } else {
        title = content.substring(0, 50).split(' ').slice(0, -1).join(' ') + "..."
      }
    }

    setIsCreatingSession(true)
    try {
      const headers: Record<string, string> = {
        "Content-Type": "application/json",
        ...getAuthHeaders()
      }
      const response = await fetch(`${API_BASE_URL}/api/v1/chat/sessions`, {
        method: "POST",
        headers,
        body: JSON.stringify({ title })
      })
      if (response.ok) {
        const session = await response.json()
        setCurrentSessionId(session.id)
        setMessages([])
        // Invalidate sessions cache since we created a new one
        try {
          const invalidateHeaders: Record<string, string> = {
            ...getAuthHeaders()
          }
          await fetch(`/api/cache/sessions`, {
            method: "DELETE",
            headers: invalidateHeaders
          })
        } catch (err) {
          console.error("Failed to invalidate sessions cache:", err)
        }
        loadChatHistory()
        return session.id
      }
    } catch (error) {
      console.error("Failed to create session:", error)
    } finally {
      setIsCreatingSession(false)
    }
    return null
  }, [getAuthHeaders, API_BASE_URL, loadChatHistory])

  // Load chat history on component mount
  useEffect(() => {
    loadChatHistory()
  }, [loadChatHistory])

  // Autocomplete functionality
  const fetchAutocomplete = useCallback(async (query: string) => {
    if (!ENABLE_AUTOCOMPLETE || !query.trim() || query.length < 2) {
      setAutocompleteSuggestions([])
      setShowAutocomplete(false)
      return
    }

    try {
      const response = await fetch(
        `${API_BASE_URL}/api/autocomplete?q=${encodeURIComponent(query)}&max_results=5&location=Kenya&language=en`
      )
      if (response.ok) {
        const data = await response.json()
        const suggestions = data.suggestions?.map((s: { text: string }) => s.text) || []
        setAutocompleteSuggestions(suggestions)
        setShowAutocomplete(suggestions.length > 0)
      }
    } catch (error) {
      console.error("Failed to fetch autocomplete:", error)
      setAutocompleteSuggestions([])
      setShowAutocomplete(false)
    }
  }, [API_BASE_URL, ENABLE_AUTOCOMPLETE])

  // Debounced autocomplete
  useEffect(() => {
    if (!ENABLE_AUTOCOMPLETE) {
      setAutocompleteSuggestions([])
      setShowAutocomplete(false)
      return
    }

    if (autocompleteTimeoutRef.current) {
      clearTimeout(autocompleteTimeoutRef.current)
    }

    if (input.trim().length >= 2) {
      autocompleteTimeoutRef.current = setTimeout(() => {
        fetchAutocomplete(input)
      }, 300)
    } else {
      setAutocompleteSuggestions([])
      setShowAutocomplete(false)
    }

    return () => {
      if (autocompleteTimeoutRef.current) {
        clearTimeout(autocompleteTimeoutRef.current)
      }
    }
  }, [input, fetchAutocomplete, ENABLE_AUTOCOMPLETE])

  const loadSession = async (sessionId: string) => {
    try {
      const headers: Record<string, string> = {
        "Content-Type": "application/json",
        ...getAuthHeaders()
      }
      // Use cache API route instead of direct backend call
      const response = await fetch(`/api/cache/sessions/${sessionId}/messages`, {
        headers
      })
      if (response.ok) {
        const sessionMessages = await response.json()
        setMessages(sessionMessages)
        setCurrentSessionId(sessionId)
        setShowHistory(false)
        // Log cache hit/miss for debugging
        const cacheStatus = response.headers.get("X-Cache")
        if (cacheStatus) {
          console.log(`Session ${sessionId} messages cache: ${cacheStatus}`)
        }
      }
    } catch (error) {
      console.error("Failed to load session:", error)
    }
  }

  const uploadFiles = useCallback(async (sessionId: string, files: File[]): Promise<string[]> => {
    const attachmentIds: string[] = []
    setUploadingFiles(true)

    try {
      for (const file of files) {
        const formData = new FormData()
        formData.append("file", file)

        const headers: Record<string, string> = {
          ...getAuthHeaders()
        }
        const response = await fetch(`${API_BASE_URL}/api/v1/chat/sessions/${sessionId}/attachments`, {
          method: "POST",
          headers,
          body: formData,
        })

        if (response.ok) {
          const data = await response.json()
          attachmentIds.push(data.attachment.id)
        } else {
          const error = await response.json()
          throw new Error(error.detail || "Failed to upload file")
        }
      }
    } finally {
      setUploadingFiles(false)
    }

    return attachmentIds
  }, [getAuthHeaders, API_BASE_URL])

  const sendMessage = useCallback(async (content: string) => {
    if (!content.trim() && selectedFiles.length === 0) return
    if (isLoading || isCreatingSession || uploadingFiles) return

    setIsLoading(true)
    try {
      let sessionId = currentSessionId
      if (!sessionId) {
        sessionId = await createNewSession(content.trim() || "File upload")
        if (!sessionId) {
          setIsLoading(false)
          return
        }
      }

      // Upload files first if any
      let attachmentIds: string[] = []
      let attachmentMetadata: Message["attachments"] = []
      if (selectedFiles.length > 0) {
        try {
          attachmentIds = await uploadFiles(sessionId, selectedFiles)
          // Fetch attachment details to display immediately
          try {
            const headers: Record<string, string> = {
              "Content-Type": "application/json",
              ...getAuthHeaders()
            }
            const attachmentPromises = attachmentIds.map(id =>
              fetch(`${API_BASE_URL}/api/v1/chat/sessions/${sessionId}/attachments/${id}`, {
                headers
              })
                .then(res => res.ok ? res.json() : null)
                .catch(() => null)
            )
            const attachmentResults = await Promise.all(attachmentPromises)
            attachmentMetadata = attachmentResults
              .filter(att => att !== null)
              .map(att => ({
                id: att.id,
                filename: att.filename,
                file_type: att.file_type,
                file_size: att.file_size,
                uploaded_at: att.uploaded_at,
                processed: att.processed || false,
                cloudinary_url: att.cloudinary_url
              }))
          } catch (error) {
            console.error("Failed to fetch attachment metadata:", error)
          }
          setSelectedFiles([]) // Clear selected files after upload
        } catch (error) {
          toast.error(error instanceof Error ? error.message : "Failed to upload files")
          setIsLoading(false)
          return
        }
      }

      const userMessage: Message = {
        id: Date.now().toString(),
        session_id: sessionId,
        role: "user",
        content: content.trim() || `Uploaded ${selectedFiles.length} file(s)`,
        created_at: new Date().toISOString(),
        saved: false,
        attachments: attachmentMetadata.length > 0 ? attachmentMetadata : undefined
      }

      setMessages(prev => [...prev, userMessage])
      setInput("")
      setIsLoading(true)

      try {
        let response;
        if (isResearchMode) {
          const headers: Record<string, string> = {
            "Content-Type": "application/x-www-form-urlencoded",
            ...getAuthHeaders()
          }
          response = await fetch(`${API_BASE_URL}/research/analyze-legal-query`, {
            method: "POST",
            headers,
            body: new URLSearchParams({
              query: content.trim()
            })
          })
        } else if (useHybrid) {
          const headers: Record<string, string> = {
            "Content-Type": "application/json",
            ...getAuthHeaders()
          }
          response = await fetch(`${API_BASE_URL}/stream/query`, {
            method: "POST",
            headers,
            body: JSON.stringify({
              query: content.trim(),
              top_k: 5,
              include_sources: true,
              stream: true
            })
          })
        } else {
          const headers: Record<string, string> = {
            "Content-Type": "application/json",
            ...getAuthHeaders()
          }
          response = await fetch(`${API_BASE_URL}/api/v1/chat/sessions/${sessionId}/messages`, {
            method: "POST",
            headers,
            body: JSON.stringify({
              content: content.trim(),
              role: "user",
              stream: true,
              attachment_ids: attachmentIds.length > 0 ? attachmentIds : undefined
            })
          })
        }

        if (response.ok) {
          if (isResearchMode) {
            const data = await response.json()
            const analysis = data.analysis || {}
            
            const queryInterpretation = analysis.query_interpretation || 'Analyzing your legal question...'
            const applicableLaws = Array.isArray(analysis.applicable_laws) 
              ? analysis.applicable_laws.join('\n- ') 
              : (analysis.applicable_laws || 'Researching relevant Kenyan laws...')
            const legalAnalysis = analysis.legal_analysis || 'Conducting detailed legal analysis...'
            const practicalGuidance = analysis.practical_guidance || {}
            const guidanceSteps = Array.isArray(practicalGuidance.steps) 
              ? practicalGuidance.steps 
              : (typeof practicalGuidance === 'string' ? [practicalGuidance] : ['Review the analysis above'])
            const guidanceSummary = practicalGuidance.summary || ''
            const additionalConsiderations = Array.isArray(analysis.additional_considerations)
              ? analysis.additional_considerations
              : (typeof analysis.additional_considerations === 'string' 
                ? [analysis.additional_considerations] 
                : ['Review all applicable laws'])
            const researchProcess = analysis.research_process || {}
            
            const researchContent = `
## 📋 Legal Research Analysis

**Your Question:** ${data.original_query || content.trim()}

---

### 🔍 Query Understanding

${queryInterpretation}

---

### 📖 Applicable Laws & Provisions

${Array.isArray(analysis.applicable_laws) 
  ? analysis.applicable_laws.map((law: string, idx: number) => `${idx + 1}. ${law}`).join('\n')
  : `- ${applicableLaws}`}

---

### ⚖️ Legal Analysis

${legalAnalysis}

---

### 🛠️ Practical Guidance

${guidanceSummary ? `**Summary:** ${guidanceSummary}\n\n` : ''}**Action Steps:**

${guidanceSteps.map((step: string, idx: number) => `${idx + 1}. ${step}`).join('\n')}

---

### ⚠️ Important Considerations

${additionalConsiderations.map((consideration: string) => `- ${consideration}`).join('\n')}

---

${researchProcess.steps_completed || researchProcess.sources_consulted ? `### 📊 Research Process

- **Steps Completed:** ${researchProcess.steps_completed || 0}
- **Actions Taken:** ${researchProcess.actions_taken || 0}
- **Sources Consulted:** ${researchProcess.sources_consulted || 0}
${researchProcess.tools_used && researchProcess.tools_used.length > 0 
  ? `- **Tools Used:** ${researchProcess.tools_used.join(', ')}` 
  : ''}

---\n` : ''}### 📝 Disclaimer

*This analysis is for informational purposes only and does not constitute legal advice. Please consult with a qualified legal professional for advice specific to your situation.*
            `.trim()
            
            const assistantMessage: Message = {
              id: Date.now().toString(),
              session_id: sessionId,
              role: "assistant",
              content: researchContent,
              created_at: new Date().toISOString(),
              model_used: data.model_used || "gemini-research",
              saved: true
            }
            setMessages(prev => [...prev, assistantMessage])
            
            setResearchResults(prev => ({
              ...prev,
              [assistantMessage.id]: data
            }))
          } else {
            const assistantMessageId = Date.now().toString()
            const assistantMessage: Message = {
              id: assistantMessageId,
              session_id: sessionId,
              role: "assistant",
              content: "",
              created_at: new Date().toISOString(),
              model_used: "streaming",
              saved: false
            }
            
            setMessages(prev => [...prev, assistantMessage])
            
            const reader = response.body?.getReader()
            const decoder = new TextDecoder()
            let accumulatedContent = ""
            const metadata: StreamMetadata = {}
            
            if (reader) {
              try {
                while (true) {
                  const { done, value } = await reader.read()
                  if (done) break
                  
                  const chunk = decoder.decode(value, { stream: true })
                  const lines = chunk.split('\n')
                  
                  for (const line of lines) {
                    if (line.startsWith('data: ')) {
                      const data = line.slice(6)
                      if (data === '[DONE]') continue
                      
                      if (data.startsWith('[DONE]')) {
                        try {
                          const parsed = JSON.parse(data.slice(7))
                          metadata.sources = parsed.sources || []
                          metadata.token_count = parsed.retrieved_chunks
                          metadata.model_used = parsed.model_used || (parsed.hybrid_used ? 'hybrid' : 'standard')
                          setMessages(prev => prev.map(msg => 
                            msg.id === assistantMessageId 
                              ? { 
                                  ...msg, 
                                  content: accumulatedContent,
                                  token_count: metadata.token_count,
                                  model_used: metadata.model_used,
                                  sources: metadata.sources,
                                  saved: true
                                }
                              : msg
                          ))
                          break
                        } catch {
                          // Fall through
                        }
                      }
                      
                      if (useHybrid && !data.startsWith('{') && !data.startsWith('[')) {
                        accumulatedContent += data
                        setMessages(prev => prev.map(msg => 
                          msg.id === assistantMessageId 
                            ? { ...msg, content: accumulatedContent }
                            : msg
                        ))
                        continue
                      }
                      
                      try {
                        const parsed = JSON.parse(data)
                        
                        if (parsed.type === 'sources') {
                          metadata.sources = parsed.sources
                          metadata.token_count = parsed.retrieved_chunks
                          metadata.model_used = parsed.model_used
                        } else if (parsed.type === 'content') {
                          accumulatedContent += parsed.content
                          setMessages(prev => prev.map(msg => 
                            msg.id === assistantMessageId 
                              ? { ...msg, content: accumulatedContent }
                              : msg
                          ))
                        } else if (parsed.type === 'done') {
                          setMessages(prev => prev.map(msg => 
                            msg.id === assistantMessageId 
                              ? { 
                                  ...msg, 
                                  content: parsed.full_answer || accumulatedContent,
                                  token_count: metadata.token_count,
                                  model_used: metadata.model_used,
                                  sources: metadata.sources,
                                  structured_response: parsed.structured_data,
                                  saved: true
                                }
                              : msg
                          ))
                          break
                        } else if (parsed.type === 'error') {
                          console.error('Streaming error:', parsed.error)
                          
                          setMessages(prev => prev.map(msg => 
                            msg.id === userMessage.id 
                              ? { ...msg, failed: true, originalQuery: content.trim() }
                              : msg
                          ))
                          
                          setMessages(prev => prev.map(msg => 
                            msg.id === assistantMessageId 
                              ? { 
                                  ...msg, 
                                  content: `Error: ${parsed.error}`,
                                  model_used: 'error',
                                  saved: true,
                                  failed: true,
                                  originalQuery: content.trim()
                                }
                              : msg
                          ))
                          break
                        }
                      } catch {
                        continue
                      }
                    }
                  }
                }
              } finally {
                reader.releaseLock()
              }
            }
          }
          // Invalidate session messages cache since new message was added
          try {
            const invalidateHeaders: Record<string, string> = {
              ...getAuthHeaders()
            }
            await Promise.all([
              fetch(`/api/cache/sessions/${sessionId}/messages`, {
                method: "DELETE",
                headers: invalidateHeaders
              }),
              // Also invalidate sessions list to capture any auto-generated titles
              fetch(`/api/cache/sessions`, {
                method: "DELETE",
                headers: invalidateHeaders
              })
            ])
          } catch (err) {
            console.error("Failed to invalidate cache:", err)
          }
          loadChatHistory()
        } else {
          setMessages(prev => prev.map(msg => 
            msg.id === userMessage.id 
              ? { ...msg, failed: true, originalQuery: content.trim() }
              : msg
          ))
          
          const errorMessage: Message = {
            id: (Date.now() + 1).toString(),
            session_id: sessionId,
            role: "assistant",
            content: isResearchMode 
              ? "Sorry, I encountered an error processing your legal research request."
              : "Sorry, I encountered an error processing your request.",
            created_at: new Date().toISOString(),
            failed: true,
            originalQuery: content.trim()
          }
          setMessages(prev => [...prev, errorMessage])
        }
      } catch (error) {
        console.error("Failed to send message:", error)
        
        setMessages(prev => prev.map(msg => 
          msg.id === userMessage.id 
            ? { ...msg, failed: true, originalQuery: content.trim() }
            : msg
        ))
        
        const errorMessage: Message = {
          id: (Date.now() + 1).toString(),
          session_id: sessionId,
          role: "assistant",
          content: isResearchMode 
            ? "Sorry, I couldn't connect to the research service. Please try again."
            : "Sorry, I couldn't connect to the server. Please try again.",
          created_at: new Date().toISOString(),
          failed: true,
          originalQuery: content.trim()
        }
        setMessages(prev => [...prev, errorMessage])
      } finally {
        setIsLoading(false)
      }
    } catch (error) {
      console.error("Failed to process message:", error)
      setIsLoading(false)
    }
  }, [currentSessionId, selectedFiles, isResearchMode, useHybrid, getAuthHeaders, API_BASE_URL, loadChatHistory, createNewSession, uploadFiles, isLoading, isCreatingSession, uploadingFiles])

  const submitFeedback = async (messageId: string, feedbackType: "like" | "dislike") => {
    try {
      const headers: Record<string, string> = {
        "Content-Type": "application/json",
        ...getAuthHeaders()
      }
      const response = await fetch(`${API_BASE_URL}/api/v1/chat/feedback`, {
        method: "POST",
        headers,
        body: JSON.stringify({
          message_id: messageId,
          feedback_type: feedbackType === "like" ? "positive" : "negative"
        })
      })
      
      if (response.ok) {
        setMessages(prev => prev.map(msg => 
          msg.id === messageId ? { ...msg, feedback_type: feedbackType } : msg
        ))
      }
    } catch (error) {
      console.error("Failed to submit feedback:", error)
    }
  }

  const copyToClipboard = async (text: string) => {
    try {
      await navigator.clipboard.writeText(text)
      toast.success("Message copied to clipboard!")
    } catch (error) {
      console.error("Failed to copy to clipboard:", error)
      toast.error("Failed to copy to clipboard")
    }
  }

  const copyFailedQuery = async (message: Message) => {
    const query = message.originalQuery || message.content
    try {
      await navigator.clipboard.writeText(query)
      toast.success("Query copied to clipboard!")
    } catch (error) {
      console.error("Failed to copy query:", error)
      toast.error("Failed to copy query")
    }
  }

  const editFailedQuery = (message: Message) => {
    const query = message.originalQuery || message.content
    setInput(query)
    setTimeout(() => {
      const inputElement = document.querySelector('textarea') as HTMLTextAreaElement
      inputElement?.focus()
    }, 100)
  }

  const resendFailedQuery = async (message: Message) => {
    const query = message.originalQuery || (message.role === "user" ? message.content : "")
    if (!query.trim()) return
    
    setMessages(prev => prev.filter(msg => 
      msg.id !== message.id && 
      !(msg.failed && (msg.originalQuery === query || (msg.role === "user" && msg.content === query)))
    ))
    
    await sendMessage(query)
  }

  const startEditingMessage = (message: Message) => {
    if (message.role !== "user") return
    setEditingMessageId(message.id)
    setEditingContent(message.content)
  }

  const cancelEditing = () => {
    setEditingMessageId(null)
    setEditingContent("")
  }

  const saveEditedMessage = async (messageId: string) => {
    if (!editingContent.trim()) return
    
    const messageIndex = messages.findIndex(m => m.id === messageId)
    if (messageIndex === -1) return

    setMessages(prev => prev.slice(0, messageIndex))
    
    setEditingMessageId(null)
    setEditingContent("")
    await sendMessage(editingContent)
  }

  const regenerateMessage = async (messageId: string) => {
    const messageIndex = messages.findIndex(m => m.id === messageId)
    if (messageIndex === -1 || messages[messageIndex].role !== "assistant") return

    let userMessageIndex = -1
    let userMessageContent = ""
    for (let i = messageIndex - 1; i >= 0; i--) {
      if (messages[i].role === "user") {
        userMessageIndex = i
        userMessageContent = messages[i].content
        break
      }
    }

    if (userMessageIndex === -1) return

    setMessages(prev => prev.slice(0, userMessageIndex + 1))
    
    setRegeneratingMessageId(messageId)
    await sendMessage(userMessageContent)
    setRegeneratingMessageId(null)
  }

  const deleteSession = async (sessionId: string) => {
    if (!confirm("Are you sure you want to delete this chat session? This action cannot be undone.")) {
      return
    }

    try {
      const headers: Record<string, string> = {
        "Content-Type": "application/json",
        ...getAuthHeaders()
      }
      const response = await fetch(`${API_BASE_URL}/chat/sessions/${sessionId}`, {
        method: "DELETE",
        headers
      })
      
      if (response.ok) {
        setChatHistory(prev => prev.filter(session => session.id !== sessionId))
        if (currentSessionId === sessionId) {
          setCurrentSessionId(null)
          setMessages([])
        }
        // Invalidate both sessions list and specific session messages cache
        try {
          const invalidateHeaders: Record<string, string> = {
            ...getAuthHeaders()
          }
          await Promise.all([
            fetch(`/api/cache/sessions`, {
              method: "DELETE",
              headers: invalidateHeaders
            }),
            fetch(`/api/cache/sessions/${sessionId}/messages`, {
              method: "DELETE",
              headers: invalidateHeaders
            })
          ])
        } catch (err) {
          console.error("Failed to invalidate cache:", err)
        }
      }
    } catch (error) {
      console.error("Failed to delete session:", error)
    }
  }

  const renameSession = async (sessionId: string, newTitle: string) => {
    try {
      const headers: Record<string, string> = {
        "Content-Type": "application/json",
        ...getAuthHeaders()
      }
      const response = await fetch(`${API_BASE_URL}/chat/sessions/${sessionId}`, {
        method: "PATCH",
        headers,
        body: JSON.stringify({ title: newTitle })
      })

      if (response.ok) {
        // Update local state
        setChatHistory(prev => prev.map(s => 
          s.id === sessionId ? { ...s, title: newTitle } : s
        ))
        
        // Invalidate sessions cache
        try {
          const invalidateHeaders: Record<string, string> = {
            ...getAuthHeaders()
          }
          await fetch(`/api/cache/sessions`, {
            method: "DELETE",
            headers: invalidateHeaders
          })
        } catch (err) {
          console.error("Failed to invalidate sessions cache:", err)
        }
        
        toast.success("Chat renamed")
      }
    } catch (error) {
      console.error("Failed to rename session:", error)
      toast.error("Failed to rename chat")
    }
  }

  const shareChat = async (options: { silent?: boolean } = {}) => {
    if (!currentSessionId) return null

    try {
      const headers: Record<string, string> = {
        "Content-Type": "application/json",
        ...getAuthHeaders()
      }
      const response = await fetch(
        `${API_BASE_URL}/api/v1/chat/share?session_id=${encodeURIComponent(currentSessionId)}`,
        {
          method: "POST",
          headers
        }
      )
      if (response.ok) {
        const data = await response.json()
        const shareUrl = `${window.location.origin}${data.share_link}`
        if (!options.silent) {
          await navigator.clipboard.writeText(shareUrl)
          toast.success("Share link copied to clipboard!")
        }
        return shareUrl
      } else {
        if (!options.silent) {
          toast.error("Failed to generate share link")
        }
      }
    } catch (error) {
      console.error("Failed to generate share link:", error)
      if (!options.silent) {
        toast.error("Failed to generate share link")
      }
    }
    return null
  }

  const generatePDF = async (messageId: string) => {
    const researchData = researchResults[messageId]
    if (!researchData) {
      toast.error("Research data not found")
      return
    }

    try {
      const response = await fetch(`${API_BASE_URL}/research/generate-pdf-report`, {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: new URLSearchParams({
          analysis_results: JSON.stringify(researchData),
          report_title: "Legal Research Report"
        })
      })

      if (response.ok) {
        const blob = await response.blob()
        const url = window.URL.createObjectURL(blob)
        const a = document.createElement('a')
        a.href = url
        a.download = 'legal_research_report.pdf'
        document.body.appendChild(a)
        a.click()
        window.URL.revokeObjectURL(url)
        document.body.removeChild(a)
        toast.success("PDF report downloaded!")
      } else {
        toast.error("Failed to generate PDF report")
      }
    } catch (error) {
      console.error("Error generating PDF:", error)
      toast.error("Error generating PDF report")
    }
  }

  const generateWord = async (messageId: string) => {
    const researchData = researchResults[messageId]
    if (!researchData) {
      toast.error("Research data not found")
      return
    }

    try {
      const response = await fetch(`${API_BASE_URL}/research/generate-word-report`, {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: new URLSearchParams({
          analysis_results: JSON.stringify(researchData),
          report_title: "Legal Research Report"
        })
      })

      if (response.ok) {
        const blob = await response.blob()
        const url = window.URL.createObjectURL(blob)
        const a = document.createElement('a')
        a.href = url
        a.download = 'legal_research_report.docx'
        document.body.appendChild(a)
        a.click()
        window.URL.revokeObjectURL(url)
        document.body.removeChild(a)
        toast.success("Word document downloaded!")
      } else {
        toast.error("Failed to generate Word document")
      }
    } catch (error) {
      console.error("Error generating Word document:", error)
      toast.error("Error generating Word document")
    }
  }

  const sanitizeForSharing = (content: string) => {
    if (!content) return ""
    return content.replace(/<[^>]+>/g, "").trim()
  }

  const ensureSharePreview = async (message: Message, platform: SharePlatform) => {
    const cached = shareCache[message.id]?.[platform]
    if (cached) return cached

    try {
      setShareSheet((prev) =>
        prev?.messageId === message.id
          ? { ...prev, isLoading: true, shareError: null, success: null, shareLink: null }
          : prev
      )

      const response = await fetch(`${API_BASE_URL}/share/format`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          answer: sanitizeForSharing(message.content),
          sources: message.sources || [],
          platform,
          query: findPreviousUserPrompt(message.id),
          include_hashtags: true
        })
      })

      if (!response.ok) {
        const detail = await response.text()
        throw new Error(detail || "Unable to format response")
      }

      const data: ShareFormatResponse = await response.json()
      setShareCache((prev) => ({
        ...prev,
        [message.id]: { ...(prev[message.id] || {}), [platform]: data }
      }))
      setShareSheet((prev) =>
        prev?.messageId === message.id ? { ...prev, preview: data, isLoading: false } : prev
      )
      return data
    } catch (error) {
      console.error("Failed to format post:", error)
      setShareSheet((prev) =>
        prev?.messageId === message.id
          ? {
              ...prev,
              isLoading: false,
              shareError:
                error instanceof Error ? error.message : "Unable to format this response right now."
            }
          : prev
      )
      return null
    }
  }

  const openShareSheet = (message: Message, platform: SharePlatform = "twitter") => {
    if (message.role !== "assistant") return

    if (shareSheet?.messageId === message.id && shareSheet.platform === platform) {
      setShareSheet(null)
      return
    }

    const cached = shareCache[message.id]?.[platform]
    setShareSheet({
      messageId: message.id,
      platform,
      preview: cached,
      isLoading: !cached,
      shareLink: null,
      shareError: null,
      success: null
    })

    if (!cached) {
      ensureSharePreview(message, platform)
    }
  }

  const changeSharePlatform = (message: Message, platform: SharePlatform) => {
    if (!shareSheet || shareSheet.messageId !== message.id) {
      openShareSheet(message, platform)
      return
    }

    const cached = shareCache[message.id]?.[platform]
    setShareSheet({
      ...shareSheet,
      platform,
      preview: cached,
      isLoading: !cached,
      shareLink: null,
      shareError: null,
      success: null
    })

    if (!cached) {
      ensureSharePreview(message, platform)
    }
  }

  const copyShareContent = async () => {
    if (!shareSheet?.preview) return
    const preview = shareSheet.preview
    const text = Array.isArray(preview.content) ? preview.content.join("\n\n") : preview.content

    try {
      await navigator.clipboard.writeText(text)
      toast.success("Formatted answer copied!")
    } catch (error) {
      console.error("Failed to copy share content:", error)
      toast.error("Unable to copy content")
    }
  }

  const openShareIntent = async (message: Message) => {
    if (!shareSheet) return
    const preview = shareSheet.preview ?? (await ensureSharePreview(message, shareSheet.platform))
    if (!preview) return

    try {
      setShareSheet((prev) =>
        prev ? { ...prev, shareLinkLoading: true, shareError: null, success: null } : prev
      )
      const sessionLink = await shareChat({ silent: true })

      const response = await fetch(`${API_BASE_URL}/share/generate-link`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          platform: shareSheet.platform,
          content: preview.content,
          url: sessionLink || undefined
        })
      })

      if (!response.ok) {
        const detail = await response.text()
        throw new Error(detail || "Unable to open share dialog")
      }

      const data = await response.json()
      setShareSheet((prev) =>
        prev
          ? {
              ...prev,
              shareLink: data.share_url,
              shareLinkLoading: false,
              success: `Share dialog ready for ${shareSheet.platform}`
            }
          : prev
      )
      window.open(data.share_url, "_blank", "noopener,noreferrer")
    } catch (error) {
      console.error("Failed to open share link:", error)
      setShareSheet((prev) =>
        prev
          ? {
              ...prev,
              shareLinkLoading: false,
              shareError:
                error instanceof Error
                  ? error.message
                  : "Unable to open the platform share dialog."
            }
          : prev
      )
    }
  }

  const generateShareImage = async (message: Message) => {
    if (!shareSheet) return
    const preview = shareSheet.preview ?? (await ensureSharePreview(message, shareSheet.platform))
    if (!preview) return

    try {
      setShareSheet((prev) =>
        prev ? { ...prev, generatingImage: true, shareError: null, success: null } : prev
      )

      const text = Array.isArray(preview.content) ? preview.content.join("\n\n") : preview.content
      const title = `AmaniQuery Insight`

      const response = await fetch(`${API_BASE_URL}/share/generate-image-from-post`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          post_content: text,
          query: title,
          color_scheme: "professional"
        })
      })

      if (!response.ok) {
        const detail = await response.text()
        throw new Error(detail || "Unable to generate image")
      }

      const data = await response.json()
      
      // Download the image
      const imageResponse = await fetch(`data:image/png;base64,${data.image_base64}`)
      const blob = await imageResponse.blob()
      const url = URL.createObjectURL(blob)
      
      const a = document.createElement('a')
      a.href = url
      a.download = `amaniquery-${message.id}.png`
      document.body.appendChild(a)
      a.click()
      document.body.removeChild(a)
      URL.revokeObjectURL(url)

      setShareSheet((prev) =>
        prev
          ? {
              ...prev,
              generatingImage: false,
              success: "Image downloaded successfully!",
              shareError: null
            }
          : prev
      )
    } catch (error) {
      console.error("Failed to generate image:", error)
      setShareSheet((prev) =>
        prev
          ? {
              ...prev,
              generatingImage: false,
              shareError:
                error instanceof Error
                  ? error.message
                  : "Unable to generate image."
            }
          : prev
      )
    }
  }

  const postDirectly = async (message: Message) => {
    if (!shareSheet) return
    const preview = shareSheet.preview ?? (await ensureSharePreview(message, shareSheet.platform))
    if (!preview) return

    // Check if user is authenticated
    const accessToken = getStoredToken(shareSheet.platform)
    if (!accessToken) {
      setShareSheet(prev => prev ? {
        ...prev,
        shareError: `Please authenticate with ${shareSheet.platform} first. Click the authenticate button below.`
      } : prev)
      return
    }

    try {
      setShareSheet((prev) =>
        prev ? { ...prev, posting: true, shareError: null, success: null } : prev
      )

      const response = await fetch(`${API_BASE_URL}/share/post`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          platform: shareSheet.platform,
          content: preview.content,
          message_id: message.id,
          access_token: accessToken
        })
      })

      if (!response.ok) {
        const detail = await response.text()
        throw new Error(detail || "Unable to post")
      }

      const data = await response.json()
      console.log('Post response:', data)
      setShareSheet((prev) =>
        prev
          ? {
              ...prev,
              posting: false,
              success: data.message || `Posted to ${shareSheet.platform} successfully`,
              shareError: null
            }
          : prev
      )
      toast.success(data.message || `Posted to ${shareSheet.platform} successfully`)
    } catch (error) {
      console.error("Failed to post to platform:", error)
      setShareSheet((prev) =>
        prev
          ? {
              ...prev,
              posting: false,
              shareError:
                error instanceof Error
                  ? error.message
                  : "Unable to post automatically. Try the share dialog instead."
            }
          : prev
      )
    }
  }

  return (
    <div className="relative flex h-screen max-h-screen bg-gradient-to-b from-background via-background/95 to-background text-foreground overflow-hidden">
      <ChatSidebar
        chatHistory={chatHistory}
        currentSessionId={currentSessionId}
        showHistory={showHistory}
        onLoadSession={loadSession}
        onDeleteSession={deleteSession}
        onRenameSession={renameSession}
        onCreateSession={() => createNewSession()}
        onCloseHistory={() => setShowHistory(false)}
      />
      
      <div className="flex-1 flex flex-col min-w-0 h-full relative">
        <ChatHeader
          isResearchMode={isResearchMode}
          useHybrid={useHybrid}
          currentSessionId={currentSessionId}
          showHistory={showHistory}
          isLoading={isLoading}
          onToggleHistory={() => setShowHistory(!showHistory)}
          onShare={() => shareChat()}
          HistoryIcon={HistoryIcon}
        />

        <div className="flex-1 overflow-y-auto px-4" ref={messagesContainerRef}>
            <AmaniMessageList
              messages={messages}
              isLoading={isLoading}
              onSendMessage={sendMessage}
              onRegenerate={regenerateMessage}
              onFeedback={submitFeedback}
              onCopy={copyToClipboard}
              onShare={openShareSheet}
              onGeneratePDF={generatePDF}
              onGenerateWord={generateWord}
              showInlineSources={showSources}
              editingMessageId={editingMessageId}
              editingContent={editingContent}
              setEditingContent={setEditingContent}
              onSaveEdit={saveEditedMessage}
              onCancelEdit={cancelEditing}
              onStartEdit={startEditingMessage}
              shareSheet={shareSheet}
              onCloseShareSheet={() => setShareSheet(null)}
              onChangeSharePlatform={changeSharePlatform}
              onCopyShareContent={copyShareContent}
              onOpenShareIntent={openShareIntent}
              onPostDirectly={postDirectly}
              onGenerateShareImage={generateShareImage}
              onAuthenticatePlatform={initiateAuth}
              platformTokens={platformTokens}
              onCopyFailedQuery={copyFailedQuery}
              onEditFailedQuery={editFailedQuery}
              onResendFailedQuery={resendFailedQuery}
            />
        </div>

        <ChatInput
          input={input}
          setInput={setInput}
          isLoading={isLoading}
          isResearchMode={isResearchMode}
          useHybrid={useHybrid}
          selectedFiles={selectedFiles}
          setSelectedFiles={setSelectedFiles}
          onSendMessage={sendMessage}
          enableAutocomplete={ENABLE_AUTOCOMPLETE}
          autocompleteSuggestions={autocompleteSuggestions}
          showAutocomplete={showAutocomplete}
          setShowAutocomplete={setShowAutocomplete}
          onToggleResearch={() => {
            setIsResearchMode(!isResearchMode)
            setUseHybrid(false)
          }}
          onToggleHybrid={() => {
            setUseHybrid(!useHybrid)
            setIsResearchMode(false)
          }}
        />
      </div>
    </div>
  )
}
