import React from "react"
import { type ChatHistory, type Message } from "~/store/option"
import { useStoreMessageOption } from "~/store/option"
import { removeMessageUsingHistoryId, saveHistory, saveMessage } from "@/db/dexie/helpers"
import { useNavigate } from "react-router-dom"
import { notification } from "antd"
import { useTranslation } from "react-i18next"
import { usePageAssist } from "@/context"
import { useWebUI } from "@/store/webui"
import { useStorage } from "@plasmohq/storage/hook"
import { useStoreChatModelSettings } from "@/store/model"
import { ChatDocuments } from "@/models/ChatTypes"
import { searchChatMode } from "./chat-modes/searchChatMode"
import { normalChatMode } from "./chat-modes/normalChatMode"
import { continueChatMode } from "./chat-modes/continueChatMode"
import { ragMode } from "./chat-modes/ragMode"
import {
  focusTextArea,
  validateBeforeSubmit,
  createSaveMessageOnSuccess,
  createSaveMessageOnError
} from "./utils/messageHelpers"
import {
  createRegenerateLastMessage,
  createEditMessage,
  createStopStreamingRequest,
  createBranchMessage
} from "./handlers/messageHandlers"
import { tabChatMode } from "./chat-modes/tabChatMode"
import { documentChatMode } from "./chat-modes/documentChatMode"
import { generateID } from "@/db/dexie/helpers"
import { UploadedFile } from "@/db/dexie/types"
import { updatePageTitle } from "@/utils/update-page-title"
import { generateTitle } from "@/services/title"

export const useMessageOption = () => {
  const {
    controller: abortController,
    setController: setAbortController,
    messages,
    setMessages
  } = usePageAssist()
  const {
    history,
    setHistory,
    setStreaming,
    streaming,
    setIsFirstMessage,
    historyId,
    setHistoryId,
    isLoading,
    setIsLoading,
    isProcessing,
    setIsProcessing,
    chatMode,
    setChatMode,
    webSearch,
    setWebSearch,
    isSearchingInternet,
    setIsSearchingInternet,
    selectedQuickPrompt,
    setSelectedQuickPrompt,
    selectedSystemPrompt,
    setSelectedSystemPrompt,
    selectedKnowledge,
    setSelectedKnowledge,
    temporaryChat,
    setTemporaryChat,
    useOCR,
    setUseOCR,
    documentContext,
    setDocumentContext,
    uploadedFiles,
    setUploadedFiles,
    contextFiles,
    setContextFiles,
    actionInfo,
    setActionInfo,
    setPendingMcpApproval,
    setFileRetrievalEnabled,
    fileRetrievalEnabled
  } = useStoreMessageOption()
  const [webuiTemporaryChat] = useStorage("webuiTemporaryChat", false)
  const [mcpHumanInLoop] = useStorage("mcpHumanInLoop", false)
  const [enableAgentWebSearch] = useStorage("enableAgentWebSearch", true)

  const currentChatModelSettings = useStoreChatModelSettings()
  const [selectedModel, setSelectedModel] = useStorage("selectedModel")
  const [defaultInternetSearchOn] = useStorage("defaultInternetSearchOn", false)
  const [speechToTextLanguage, setSpeechToTextLanguage] = useStorage(
    "speechToTextLanguage",
    "en-US"
  )
  const { ttsEnabled } = useWebUI()

  const { t } = useTranslation("option")

  const navigate = useNavigate()
  const textareaRef = React.useRef<HTMLTextAreaElement>(null)

  const handleFocusTextArea = () => focusTextArea(textareaRef)

  const handleFileUpload = async (file: File) => {
    try {
      const isImage = file.type.startsWith("image/")

      if (isImage) {
        return file
      }

      const maxSize = 10 * 1024 * 1024
      if (file.size > maxSize) {
        notification.error({
          message: "File Too Large",
          description: "File size must be less than 10MB"
        })
        return
      }

      const fileId = generateID()

      const { processFileUpload } = await import("~/utils/file-processor")
      const source = await processFileUpload(file)

      const uploadedFile: UploadedFile = {
        id: fileId,
        filename: file.name,
        type: file.type,
        content: source.content,
        size: file.size,
        uploadedAt: Date.now(),
        processed: false
      }

      setUploadedFiles([...uploadedFiles, uploadedFile])
      setContextFiles([...contextFiles, uploadedFile])

      return file
    } catch (error) {
      console.error("Error uploading file:", error)
      notification.error({
        message: "Upload Failed",
        description: "Failed to upload file. Please try again."
      })
      throw error
    }
  }

  const removeUploadedFile = async (fileId: string) => {
    setUploadedFiles(uploadedFiles.filter((f) => f.id !== fileId))
    setContextFiles(contextFiles.filter((f) => f.id !== fileId))
  }

  const clearUploadedFiles = () => {
    setUploadedFiles([])
  }

  const handleSetFileRetrievalEnabled = async (enabled: boolean) => {
    setFileRetrievalEnabled(enabled)
  }

  const clearChat = () => {
    stopStreamingRequest()
    navigate("/")
    setMessages([])
    setHistory([])
    setHistoryId(null)
    setIsFirstMessage(true)
    setIsLoading(false)
    setIsProcessing(false)
    setStreaming(false)
    setContextFiles([])
    updatePageTitle()
    currentChatModelSettings.reset()
    // textareaRef?.current?.focus()
    if (defaultInternetSearchOn) {
      setWebSearch(true)
    }
    handleFocusTextArea()
    setDocumentContext(null)
    // Clear uploaded files
    setUploadedFiles([])
    setFileRetrievalEnabled(false)
    setActionInfo(null)
    setPendingMcpApproval(null)
    if (webuiTemporaryChat) {
      setTemporaryChat(true)
    }
  }

  const saveMessageOnSuccess = createSaveMessageOnSuccess(
    temporaryChat,
    setHistoryId as (id: string) => void
  )
  const saveMessageOnError = createSaveMessageOnError(
    temporaryChat,
    history,
    setHistory,
    setHistoryId as (id: string) => void
  )

  const validateBeforeSubmitFn = React.useCallback(
    () => validateBeforeSubmit(selectedModel, t),
    [selectedModel, t]
  )

  const onSubmit = async ({
    message,
    image,
    images,
    isRegenerate = false,
    messages: chatHistory,
    memory,
    controller,
    isContinue,
    docs
  }: {
    message: string
    image: string
    images?: string[]
    isRegenerate?: boolean
    isContinue?: boolean
    messages?: Message[]
    memory?: ChatHistory
    controller?: AbortController
    docs?: ChatDocuments
  }) => {
    setStreaming(true)
    let signal: AbortSignal
    if (!controller) {
      const newController = new AbortController()
      signal = newController.signal
      setAbortController(newController)
    } else {
      setAbortController(controller)
      signal = controller.signal
    }

    const chatModeParams = {
      selectedModel,
      useOCR,
      selectedSystemPrompt,
      selectedKnowledge,
      currentChatModelSettings,
      setMessages,
      setIsSearchingInternet,
      saveMessageOnSuccess,
      saveMessageOnError,
      setHistory,
      setIsProcessing,
      setStreaming,
      setAbortController,
      historyId,
      setHistoryId,
      fileRetrievalEnabled,
      setActionInfo,
      webSearch,
      temporaryChat,
      requireMcpApproval: mcpHumanInLoop,
      messageSource: "web-ui" as const
    }

    try {
      if (isContinue) {
        await continueChatMode(
          chatHistory || messages,
          memory || history,
          signal,
          chatModeParams
        )
        return
      }
      // console.log("contextFiles", contextFiles)
      if (contextFiles.length > 0) {
        await documentChatMode(
          message,
          image,
          isRegenerate,
          chatHistory || messages,
          memory || history,
          signal,
          contextFiles,
          chatModeParams
        )
        // setFileRetrievalEnabled(false)
        return
      }

      if (docs?.length > 0 || documentContext?.length > 0) {
        const processingTabs = docs || documentContext || []

        if (docs?.length > 0) {
          setDocumentContext(
            Array.from(new Set([...(documentContext || []), ...docs]))
          )
        }
        await tabChatMode(
          message,
          image,
          processingTabs,
          isRegenerate,
          chatHistory || messages,
          memory || history,
          signal,
          chatModeParams
        )
        return
      }

      if (selectedKnowledge) {
        await ragMode(
          message,
          image,
          isRegenerate,
          chatHistory || messages,
          memory || history,
          signal,
          chatModeParams
        )
      } else {
        const useAgentWebSearch = webSearch && enableAgentWebSearch
        if (webSearch && !useAgentWebSearch) {
          // Include images array in search mode
          const enhancedSearchChatModeParams = {
            ...chatModeParams,
            images: images
          }

          await searchChatMode(
            message,
            image,
            isRegenerate,
            chatHistory || messages,
            memory || history,
            signal,
            enhancedSearchChatModeParams
          )
        } else {
          // Include uploaded files info and images array in normal mode
          const enhancedChatModeParams = {
            ...chatModeParams,
            uploadedFiles: uploadedFiles,
            images: images,
            webSearchAsTool: useAgentWebSearch
          }

          await normalChatMode(
            message,
            image,
            isRegenerate,
            chatHistory || messages,
            memory || history,
            signal,
            enhancedChatModeParams
          )
        }
      }
    } catch (e: any) {
      notification.error({
        message: t("error"),
        description: e?.message || t("somethingWentWrong")
      })
      setIsProcessing(false)
      setStreaming(false)
    }
  }

  const messagesRef = React.useRef(messages)
  const historyRef = React.useRef(history)
  const historyIdRef = React.useRef(historyId)
  const onSubmitRef = React.useRef(onSubmit)

  React.useEffect(() => {
    messagesRef.current = messages
  }, [messages])

  React.useEffect(() => {
    historyRef.current = history
  }, [history])

  React.useEffect(() => {
    historyIdRef.current = historyId
  }, [historyId])

  React.useEffect(() => {
    onSubmitRef.current = onSubmit
  }, [onSubmit])

  const getMessages = React.useCallback(() => messagesRef.current, [])
  const getHistory = React.useCallback(() => historyRef.current, [])
  const getHistoryId = React.useCallback(() => historyIdRef.current, [])
  const submitWithCurrentState = React.useCallback(
    (params: any) => onSubmitRef.current(params),
    []
  )

  const regenerateLastMessage = React.useMemo(
    () =>
      createRegenerateLastMessage({
        validateBeforeSubmitFn,
        history: getHistory,
        messages: getMessages,
        setHistory,
        setMessages,
        historyId: getHistoryId,
        removeMessageUsingHistoryIdFn: removeMessageUsingHistoryId,
        onSubmit: submitWithCurrentState
      }),
    [
      validateBeforeSubmitFn,
      getHistory,
      getMessages,
      setHistory,
      setMessages,
      getHistoryId,
      submitWithCurrentState
    ]
  )

  const stopStreamingRequest = createStopStreamingRequest(
    abortController,
    setAbortController
  )

  const editMessage = React.useMemo(
    () =>
      createEditMessage({
        messages: getMessages,
        history: getHistory,
        setMessages,
        setHistory,
        historyId: getHistoryId,
        validateBeforeSubmitFn,
        onSubmit: submitWithCurrentState
      }),
    [
      getMessages,
      getHistory,
      setMessages,
      setHistory,
      getHistoryId,
      validateBeforeSubmitFn,
      submitWithCurrentState
    ]
  )

  const createChatBranch = React.useMemo(
    () =>
      createBranchMessage({
        historyId: null,
        getHistoryId,
        setHistory,
        setHistoryId,
        setMessages,
        setContext: setContextFiles,
        setSelectedSystemPrompt,
        setSystemPrompt: currentChatModelSettings.setSystemPrompt
      }),
    [
      getHistoryId,
      setHistory,
      setHistoryId,
      setMessages,
      setContextFiles,
      setSelectedSystemPrompt,
      currentChatModelSettings.setSystemPrompt
    ]
  )

  const saveTemporaryChat = async () => {
    if (!temporaryChat || messages.length === 0) {
      return
    }

    try {
      // Generate title from the first user message
      const firstUserMessage = messages.find((msg) => !msg.isBot)?.message || "Untitled Chat"
      const title = await generateTitle(selectedModel, history, firstUserMessage)

      // Determine message source based on context
      const messageSource = "web-ui" as const

      // Create new history record
      const newHistory = await saveHistory(
        title,
        chatMode === "rag",
        messageSource
      )

      let timeOffset = 0

      // Save all messages to the new history
      for (const msg of messages) {
        await saveMessage({
          history_id: newHistory.id,
          name: selectedModel,
          role:
            msg.messageKind === "tool_result"
              ? "tool"
              : msg.isBot
                ? "assistant"
                : "user",
          content: msg.message,
          images: msg.images || [],
          source: msg.sources || [],
          time: ++timeOffset,
          message_type: "normal",
          generationInfo: msg.generationInfo,
          reasoning_time_taken: msg.reasoning_time_taken || 0,
          documents: msg.documents,
          messageKind: msg.messageKind,
          toolCalls: msg.toolCalls,
          toolCallId: msg.toolCallId,
          toolName: msg.toolName,
          toolServerName: msg.toolServerName,
          toolError: msg.toolError
        })
      }

      // Update state to convert temporary chat to permanent
      setHistoryId(newHistory.id)
      setTemporaryChat(false)
      updatePageTitle(title)

      // Show success notification
      notification.success({
        message: t("chatSaved"),
        description: t("temporaryChatSavedSuccessfully")
      })

      return newHistory.id
    } catch (error) {
      console.error("Error saving temporary chat:", error)
      notification.error({
        message: t("error"),
        description: t("failedToSaveTemporaryChat")
      })
    }
  }

  return {
    editMessage,
    messages,
    setMessages,
    onSubmit,
    setStreaming,
    streaming,
    setHistory,
    historyId,
    setHistoryId,
    setIsFirstMessage,
    isLoading,
    setIsLoading,
    isProcessing,
    stopStreamingRequest,
    clearChat,
    selectedModel,
    setSelectedModel,
    chatMode,
    setChatMode,
    speechToTextLanguage,
    setSpeechToTextLanguage,
    regenerateLastMessage,
    webSearch,
    setWebSearch,
    isSearchingInternet,
    setIsSearchingInternet,
    selectedQuickPrompt,
    setSelectedQuickPrompt,
    selectedSystemPrompt,
    setSelectedSystemPrompt,
    textareaRef,
    selectedKnowledge,
    setSelectedKnowledge,
    ttsEnabled,
    temporaryChat,
    setTemporaryChat,
    useOCR,
    setUseOCR,
    defaultInternetSearchOn,
    history,
    uploadedFiles,
    fileRetrievalEnabled,
    setFileRetrievalEnabled: handleSetFileRetrievalEnabled,
    handleFileUpload,
    removeUploadedFile,
    clearUploadedFiles,
    actionInfo,
    setActionInfo,
    setContextFiles,
    createChatBranch,
    webuiTemporaryChat,
    saveTemporaryChat
  }
}
