'use client'

import { useEffect, useRef, useState, useCallback } from 'react'
import { useChatStore } from '@/lib/store'
import { MessageList } from './message-list'
import { ChatInput, PromptSuggestion } from './chat-input'
import { ChatHeader } from './chat-header'
import { WelcomeScreen } from './welcome-screen'
import { QuestionFlow } from './question-flow'
import { useQuestionFlow } from '@/hooks/use-question-flow'
import type { Message } from '@/lib/types'
import { MessageStatus } from '@/lib/types'
import { generateUUID } from '@/lib/utils'
import { sessionService } from '@/services/session-service'
import { messageService } from '@/services/message-service'
import { handleStreamEvent } from '@/lib/stream-event-handler'

export function ChatArea() {
  const [initialResolved, setInitialResolved] = useState(false)
  const [presetPrompts, setPresetPrompts] = useState<PromptSuggestion[]>([])
  const {
    conversations,
    currentConversationId,
    addMessage,
    updateMessage,
    deleteMessage,
    setStreaming,
    loadMoreMessages,
  } = useChatStore()

  // 问题模式 hook
  const {
    hasActiveQuestions,
    activeQuestions,
    activeQuestionId,
    handleSubmitAnswers,
    handleSkipQuestions,
    submitting: submittingQuestions,
    submitError,
  } = useQuestionFlow()

  // 添加预设提示词
  const handleAddPresetPrompt = useCallback((prompt: PromptSuggestion) => {
    setPresetPrompts(prev => {
      // 避免重复添加
      if (prev.some(p => p.id === prompt.id)) {
        return prev
      }
      return [...prev, prompt]
    })
  }, [])

  // 删除预设提示词
  const handleRemovePresetPrompt = useCallback((promptId: string) => {
    setPresetPrompts(prev => prev.filter(p => p.id !== promptId))
  }, [])

  // 清空所有预设提示词
  const handleClearPresetPrompts = useCallback(() => {
    setPresetPrompts([])
  }, [])

  useEffect(() => {
    const params = new URLSearchParams(window.location.search)
    const urlAgentId = params.get('agent')
    const urlSessionId = params.get('session')
    if (urlAgentId && urlSessionId) {
      useChatStore
        .getState()
        .refreshConversation(urlAgentId, urlSessionId)
        .finally(() => setInitialResolved(true))
    } else if (urlAgentId) {
      useChatStore.getState().setCurrentAgent(urlAgentId)
      setInitialResolved(true)
    } else {
      setInitialResolved(true)
    }
  }, [])

  const currentConversation = conversations.find(c => c.id === currentConversationId)
  const messages = currentConversation?.messages || []

  const scrollRef = useRef<HTMLDivElement>(null)

  const [loadingMessages, setLoadingMessages] = useState(false)
  const [loadingMore, setLoadingMore] = useState(false)
  const loadedSessionIds = useRef<Set<string>>(new Set())
  const skipAutoScroll = useRef(false)
  const scrollHeightBeforeLoad = useRef(0)

  // 用 ref 存储 scroll handler 需要的值,handleScroll 内部通过 ref 读取最新数据
  const scrollCtx = useRef({
    hasMore: false,
    agentId: '',
    sessionId: '',
    messages: [] as Message[],
    cooldown: false,
  })
  useEffect(() => {
    scrollCtx.current.hasMore = currentConversation?.hasMore ?? false
    scrollCtx.current.agentId = currentConversation?.agentId ?? ''
    scrollCtx.current.sessionId = currentConversation?.sessionId ?? ''
  }, [currentConversation?.hasMore, currentConversation?.agentId, currentConversation?.sessionId])
  useEffect(() => {
    scrollCtx.current.messages = messages
  }, [messages])
  // 记录本地创建的信息ids,避免触发reconnect的第二条sse连接
  const locallyCreatedMessageIds = useRef<Set<string>>(new Set())
  const reconnectRetryRef = useRef(0)
  const reconnectTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  useEffect(() => {
    if (!currentConversation) return
    if (currentConversation.messages.length > 0) return
    if (!currentConversation.sessionId || !currentConversation.agentId) return

    // 避免重复请求空会话
    if (loadedSessionIds.current.has(currentConversation.sessionId)) return
    loadedSessionIds.current.add(currentConversation.sessionId)

    let cancelled = false
    setLoadingMessages(true)
    sessionService
      .getConversation(currentConversation.agentId, currentConversation.sessionId)
      .then(detail => {
        if (cancelled) return
        const latestConversation = useChatStore
          .getState()
          .conversations.find(c => c.id === currentConversation.id)
        if (
          !latestConversation ||
          latestConversation.messages.length > 0 ||
          latestConversation.isStreaming
        ) {
          return
        }
        const msgs = (detail.messages || []).map((msg: any) => sessionService.transformMessage(msg))
        const hasStreaming = msgs.some((m: Message) => m.isStreaming)
        if (hasStreaming && currentConversation.sessionId) {
          loadedSessionIds.current.delete(currentConversation.sessionId)
        }
        useChatStore.setState(s => ({
          conversations: s.conversations.map(c =>
            c.id === currentConversation.id
              ? {
                  ...c,
                  messages: msgs,
                  updatedAt: new Date(detail.updated_at),
                  isStreaming: hasStreaming,
                  hasMore: detail.has_more ?? false,
                }
              : c
          ),
        }))
      })
      .catch(err => {
        console.error('Failed to load conversation messages:', err)
      })
      .finally(() => {
        if (!cancelled) setLoadingMessages(false)
      })
    return () => {
      cancelled = true
    }
  }, [currentConversation?.id])

  const loadMore = useCallback(() => {
    const el = scrollRef.current
    if (!el) return
    const ctx = scrollCtx.current
    if (!ctx.hasMore || ctx.cooldown) return

    const oldestMsg = ctx.messages[0]
    if (!oldestMsg?.timestamp || !ctx.agentId || !ctx.sessionId) return

    ctx.cooldown = true
    scrollHeightBeforeLoad.current = el.scrollHeight
    setLoadingMore(true)
    skipAutoScroll.current = true

    const before =
      oldestMsg.timestamp instanceof Date
        ? oldestMsg.timestamp.toISOString()
        : new Date(oldestMsg.timestamp).toISOString()
    loadMoreMessages(ctx.agentId, ctx.sessionId, before).finally(() => {
      setLoadingMore(false)
      setTimeout(() => {
        scrollCtx.current.cooldown = false
      }, 500)
    })
  }, [loadMoreMessages])

  // 滚动到顶部时自动加载更早的消息
  const handleScroll = useCallback(() => {
    const el = scrollRef.current
    if (!el) return
    if (el.scrollTop > 5) return
    loadMore()
  }, [loadMore])

  // 重连,恢复流式响应
  const streamingMsg = messages.find(m => m.isStreaming)
  useEffect(() => {
    if (!streamingMsg || !currentConversation?.sessionId || !currentConversation?.agentId) return
    if (!currentConversationId) return
    if (currentConversation.skipReconnect) return
    if (streamingMsg.skipReconnect) return
    if (locallyCreatedMessageIds.current.has(streamingMsg.id)) return

    const agentId = currentConversation.agentId
    const sessionId = currentConversation.sessionId
    const msgId = streamingMsg.id
    let cancelled = false

    updateMessage(currentConversationId, msgId, {
      content: '',
      events: [],
    })
    setStreaming(currentConversationId, true)

    const MAX_RETRIES = 3
    const BASE_DELAY = 1000

    const attemptReconnect = (attempt: number) => {
      if (cancelled) return
      messageService
        .reconnectStream(agentId, sessionId, eventData => {
          if (cancelled) return
          handleStreamEvent(eventData, currentConversationId, msgId, updateMessage, setStreaming)
        })
        .then(() => {
          if (!cancelled) reconnectRetryRef.current = 0
        })
        .catch(err => {
          if (cancelled) return
          console.error('Reconnect stream failed:', err)
          if (attempt < MAX_RETRIES) {
            const delay = BASE_DELAY * Math.pow(2, attempt - 1)
            reconnectTimerRef.current = setTimeout(() => attemptReconnect(attempt + 1), delay)
          } else {
            console.error('Reconnect stream failed after max retries')
            updateMessage(currentConversationId, msgId, {
              isStreaming: false,
              status: MessageStatus.ERROR,
              content:
                'Sorry, there was an error reconnecting the stream. Please refresh and try again.',
            })
            setStreaming(currentConversationId, false)
          }
        })
    }

    reconnectRetryRef.current = 1
    attemptReconnect(1)

    return () => {
      cancelled = true
      if (reconnectTimerRef.current) {
        clearTimeout(reconnectTimerRef.current)
      }
    }
  }, [streamingMsg?.id, currentConversationId])

  const scrollToBottom = useCallback(() => {
    requestAnimationFrame(() => {
      if (scrollRef.current) {
        scrollRef.current.scrollTop = scrollRef.current.scrollHeight
      }
    })
  }, [])

  // 标记是否已完成首次滚动到底部
  const initialScrollDone = useRef(false)

  // 首次内容就绪时滚动到底部
  useEffect(() => {
    if (!initialResolved) return
    if (loadingMessages) return
    if (messages.length === 0) return
    if (initialScrollDone.current) return

    initialScrollDone.current = true

    // 使用 requestAnimationFrame 确保 DOM 布局完成后滚动
    scrollToBottom()
  }, [initialResolved, loadingMessages, messages.length])

  // 新消息时自动滚动到底部(prepend 历史消息时恢复滚动位置)
  useEffect(() => {
    if (!scrollRef.current) return
    if (!initialScrollDone.current) return

    if (skipAutoScroll.current) {
      skipAutoScroll.current = false
      // 恢复滚动位置:新加载内容插入顶部后,保持原先可见的消息不跳动
      if (scrollHeightBeforeLoad.current > 0) {
        requestAnimationFrame(() => {
          if (scrollRef.current) {
            const heightDelta = scrollRef.current.scrollHeight - scrollHeightBeforeLoad.current
            scrollRef.current.scrollTop = heightDelta
            scrollHeightBeforeLoad.current = 0
          }
        })
      }
      return
    }
    scrollToBottom()
  }, [messages])

  const handleSendMessage = async (content: string, attachments?: File[]) => {
    let convId = currentConversationId

    if (!convId) {
      const state = useChatStore.getState()
      const agentId = state.currentAgentId
      if (!agentId) return
      const agent = state.agents.find(a => a.id === agentId)
      convId = state.createLocalConversation(agentId, agent?.name)
    }

    // Add user message
    const userMessage: Message = {
      id: generateUUID(),
      role: 'user',
      content,
      timestamp: new Date(),
      attachments: attachments?.map(file => ({
        id: generateUUID(),
        name: file.name,
        type: file.type.startsWith('image/') ? 'image' : 'file',
        size: file.size,
      })),
    }
    addMessage(convId, userMessage)

    await streamResponse(content, convId)
  }

  const streamResponse = useCallback(
    async (content: string, convId: string) => {
      const { currentAgentId, sendMessageToAgent, createNewSession, initializeAgent } =
        useChatStore.getState()

      let agentId = currentAgentId

      if (!agentId) {
        try {
          const defaultAgent = await initializeAgent({
            name: 'Default Agent',
            adapterType: 'openclaw',
            sandboxType: 'docker',
            idleTimeoutSeconds: 300,
          })
          agentId = defaultAgent.id
        } catch (error) {
          console.error('Failed to create default agent:', error)
          return
        }
      }

      // Ensure there's an active session
      const currentConv = useChatStore.getState().conversations.find(c => c.id === convId)
      let sessionId = currentConv?.sessionId
      if (!sessionId) {
        try {
          const session = await createNewSession(agentId)
          sessionId = session.id
        } catch (error) {
          console.error('Failed to create session:', error)
          return
        }
        // Persist sessionId back to the conversation for future messages
        useChatStore.getState().assignSessionToConversation(convId, sessionId)
      }

      setStreaming(convId, true)

      const thinkingMessageId = generateUUID()
      const thinkingMessage: Message = {
        id: thinkingMessageId,
        role: 'assistant',
        content: '',
        timestamp: new Date(),
        isStreaming: true,
        status: MessageStatus.GENERATING,
      }
      addMessage(convId, thinkingMessage)
      locallyCreatedMessageIds.current.add(thinkingMessageId)

      try {
        // 创建助手消息ID,用于后续更新
        let assistantMessageId: string | null = null
        let assistantMessage: Message | null = null

        // 发送消息到 agent,使用实时回调处理流式事件
        await sendMessageToAgent(agentId, sessionId, content, eventData => {
          // 当收到第一个事件时,删除思考中消息并创建实际的助手消息
          if (!assistantMessageId) {
            // 删除思考中消息
            deleteMessage(convId, thinkingMessageId)
            locallyCreatedMessageIds.current.delete(thinkingMessageId)

            // 创建新的助手消息
            assistantMessageId = generateUUID()
            assistantMessage = {
              id: assistantMessageId,
              role: 'assistant',
              content: '',
              timestamp: new Date(),
              isStreaming: true,
              status: MessageStatus.GENERATING,
              toolCalls: [],
              events: [],
            }
            addMessage(convId, assistantMessage)
            locallyCreatedMessageIds.current.add(assistantMessageId)
          }

          if (assistantMessageId) {
            handleStreamEvent(
              eventData,
              convId,
              assistantMessageId,
              updateMessage,
              setStreaming,
              locallyCreatedMessageIds
            )
          }
        })
      } catch (error) {
        console.error('Failed to send message:', error)
        deleteMessage(convId, thinkingMessageId)
        locallyCreatedMessageIds.current.clear()
        const errorMessageId = generateUUID()
        const errorMessage: Message = {
          id: errorMessageId,
          role: 'assistant',
          content: 'Sorry, there was an error sending your message. Please try again.',
          timestamp: new Date(),
          isStreaming: false,
          status: MessageStatus.ERROR,
        }
        addMessage(convId, errorMessage)
        setStreaming(convId, false)
      }
    },
    [addMessage, updateMessage, deleteMessage, setStreaming]
  )

  const handleRegenerate = useCallback(
    async (assistantMessageId: string) => {
      if (!currentConversationId) return

      // 删除当前 assistant 消息
      deleteMessage(currentConversationId, assistantMessageId)

      // 用系统提示重新发送(不创建新用户消息,对用户不可见)
      const regenerateContent = '/regenerate'
      await streamResponse(regenerateContent, currentConversationId)
    },
    [currentConversationId, deleteMessage, streamResponse]
  )

  if (!initialResolved) {
    return (
      <div className="flex h-full flex-col bg-background">
        <ChatHeader conversation={currentConversation} />
        <div className="flex flex-1 items-center justify-center">
          <div className="flex flex-col items-center gap-3 text-muted-foreground">
            <div className="h-6 w-6 animate-spin rounded-full border-2 border-primary border-t-transparent" />
            <p className="text-sm">加载中...</p>
          </div>
        </div>
      </div>
    )
  }

  if (messages.length === 0 && !loadingMessages) {
    return (
      <div className="flex h-full flex-col bg-background">
        <ChatHeader conversation={currentConversation} />
        <WelcomeScreen onAddPrompt={handleAddPresetPrompt} />
        <div className="border-t border-border p-4">
          <ChatInput
            onSend={handleSendMessage}
            presetPrompts={presetPrompts}
            onRemovePresetPrompt={handleRemovePresetPrompt}
            onClearPresetPrompts={handleClearPresetPrompts}
          />
        </div>
      </div>
    )
  }

  if (loadingMessages) {
    return (
      <div className="flex h-full flex-col bg-background">
        <ChatHeader conversation={currentConversation} />
        <div className="flex flex-1 items-center justify-center">
          <div className="flex flex-col items-center gap-3 text-muted-foreground">
            <div className="h-6 w-6 animate-spin rounded-full border-2 border-primary border-t-transparent" />
            <p className="text-sm">加载历史会话中...</p>
          </div>
        </div>
        <div className="border-t border-border p-4">
          <ChatInput
            onSend={handleSendMessage}
            presetPrompts={presetPrompts}
            onRemovePresetPrompt={handleRemovePresetPrompt}
            onClearPresetPrompts={handleClearPresetPrompts}
          />
        </div>
      </div>
    )
  }

  return (
    <div className="flex h-full flex-col bg-background">
      <ChatHeader conversation={currentConversation} />
      <div
        ref={scrollRef}
        onScroll={handleScroll}
        className="flex-1 overflow-y-auto scrollbar-thin"
      >
        {loadingMore && (
          <div className="flex items-center justify-center py-3">
            <div className="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent" />
            <span className="ml-2 text-xs text-muted-foreground">加载更早的消息...</span>
          </div>
        )}
        {currentConversation?.hasMore && !loadingMore && (
          <div className="flex items-center justify-center py-2">
            <button
              className="text-xs text-muted-foreground hover:text-foreground transition-colors"
              onClick={loadMore}
            >
              查看更早的消息
            </button>
          </div>
        )}
        <MessageList
          messages={messages}
          onRegenerate={handleRegenerate}
          agentName={currentConversation?.agentName}
        />
      </div>
      <div className="border-t border-border p-4">
        {hasActiveQuestions && activeQuestions && activeQuestionId ? (
          <QuestionFlow
            questions={activeQuestions}
            questionId={activeQuestionId}
            submitting={submittingQuestions}
            submitError={submitError}
            onSubmit={handleSubmitAnswers}
            onSkip={handleSkipQuestions}
          />
        ) : (
          <ChatInput
            onSend={handleSendMessage}
            presetPrompts={presetPrompts}
            onRemovePresetPrompt={handleRemovePresetPrompt}
            onClearPresetPrompts={handleClearPresetPrompts}
          />
        )}
      </div>
    </div>
  )
}