import {
  useContext,
  useEffect,
  useState,
  useCallback,
  useRef,
  LegacyRef,
} from "react"
import ReactMarkdown from "react-markdown"
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
import { prism } from "react-syntax-highlighter/dist/esm/styles/prism"
import remarkGfm from "remark-gfm"
import { SidebarContext } from "../../side-bar-provider/side-bar.context"
import useWindowDimensions from "../../../hooks/use-window-dimensions.hook"
import { useAccountUser } from "../../../hooks/use-user.hook"
import { DashboardInput } from "../dashboard-input/dashboard-input.component"
import { DashboardPageAction } from "../dashboard-page-action/dashboard-page-action.component"
import { Icon } from "../../../ui-component/icon/icon.component"
import { Config } from "../../../utils/config"
import styles from "./dashboard-message.module.css"
import { useNavigate, useParams } from "react-router-dom"
import { RoomType } from "../../../types/room.type"
import { MessageType } from "../../../types/message.type"

type Message = {
  sender: string
  text: string
}

export function DashboardMessageRoom() {
  // ---------------------------------------------------------------------------
  // variables
  // ---------------------------------------------------------------------------

  const { width: screenWidth } = useWindowDimensions()
  const { isSideBarOpen, setIsSideBarOpen } = useContext(SidebarContext)
  const accountUser = useAccountUser()
  const navigate = useNavigate()
  const { roomId } = useParams()

  const [messages, setMessages] = useState<MessageType[]>([])
  const [userMessage, setUserMessage] = useState("")
  const [typingMessage, setTypingMessage] = useState<string | null>(null)

  const messagesEndRef = useRef<HTMLDivElement | null>(null)

  // ---------------------------------------------------------------------------
  // effects
  // ---------------------------------------------------------------------------

  useEffect(() => {
    if (screenWidth <= 900) {
      if (isSideBarOpen) setIsSideBarOpen(false)
    } else {
      if (!isSideBarOpen) setIsSideBarOpen(true)
    }
  }, [screenWidth])

  useEffect(() => {
    if (messagesEndRef.current) {
      messagesEndRef.current.scrollIntoView({ behavior: "smooth" })
    }
  }, [messages, typingMessage])

  useEffect(() => {
    const fetchMessages = async () => {
      if (roomId) {
        const storedRooms = localStorage.getItem("rooms")
        const rooms = storedRooms ? JSON.parse(storedRooms) : []
        const room = rooms.find((room: RoomType) => room.id === roomId)
        if (room) {
          setMessages(room.messages)
        }
      }
    }

    fetchMessages()
  }, [roomId])

  // ---------------------------------------------------------------------------
  // functions
  // ---------------------------------------------------------------------------

  function updateLocalMessages(updatedMessages: Message[], roomId: string) {
    const storedRooms = localStorage.getItem("rooms")
    const rooms = storedRooms ? JSON.parse(storedRooms) : []
    const updatedRooms = rooms.map((room: RoomType) => {
      if (room.id === roomId) {
        return { ...room, messages: updatedMessages }
      }
      return room
    })
    localStorage.setItem("rooms", JSON.stringify(updatedRooms))
  }

  const sendVoiceMessage = useCallback(async (file: File) => {
    if (!file) return

    const formData = new FormData()
    formData.append("file", file)

    const response = await fetch(`${Config.url}/api/gptTeacher/voiceMessage`, {
      method: "POST",
      body: formData,
      credentials: "include",
    })

    const reader = response.body?.getReader()
    if (reader) {
      const decoder = new TextDecoder("utf-8")
      let botMessage = ""

      while (true) {
        const { value, done } = await reader.read()
        if (done) break
        botMessage += decoder.decode(value)
        setTypingMessage(botMessage)
      }

      setMessages((prevMessages) => [
        ...prevMessages,
        { sender: "bot", text: botMessage },
      ])
      setTypingMessage(null)
    }
  }, [])

  const sendMessage = useCallback(async () => {
    if (!userMessage.trim() || !accountUser || !roomId) return

    const newMessage: MessageType = {
      id: "",
      created_at: 0,
      roomId: roomId,
      senderId: accountUser.id,
      text: userMessage,
    }
    const updatedMessages = [...messages, newMessage]
    setMessages(updatedMessages)

    const sendTextMessage = {
      id: String(Date.now()),
      text: userMessage,
      roomId: roomId,
      senderId: accountUser?.id,
    }

    const response = await fetch(`${Config.url}/api/gptTeacher/message`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        message: sendTextMessage,
      }),
      credentials: "include",
    })

    const reader = response.body?.getReader()
    if (reader) {
      const decoder = new TextDecoder("utf-8")
      let botMessage = ""

      while (true) {
        const { value, done } = await reader.read()
        if (done) break

        botMessage += decoder.decode(value)
        setTypingMessage(botMessage)
      }

      const finalUpdatedMessages = [
        ...updatedMessages,
        {
          id: "",
          created_at: 0,
          roomId: roomId,
          senderId: !accountUser.id,
          text: botMessage,
        },
      ]
      setMessages(finalUpdatedMessages)
      updateLocalMessages(finalUpdatedMessages, roomId!)
      setTypingMessage(null)
    }

    setUserMessage("")
  }, [userMessage, messages, roomId])

  function renderMessage(message: MessageType, index: number) {
    const isBot = message.senderId !== accountUser?.id
    return (
      <div
        key={index}
        style={{
          width: "100%",
          display: "flex",
          justifyContent: isBot ? "flex-start" : "flex-end",
          gap: "1.3rem",
        }}
      >
        {isBot && (
          <div className={styles.botIcon}>
            <img src="../../../public/bot-logo.svg" alt="logo" />
          </div>
        )}
        <div className={`${styles.chatMessage} ${styles.user}`}>
          <ReactMarkdown
            className={styles.messageText}
            remarkPlugins={[remarkGfm]}
            children={message.text}
            components={{
              code(props) {
                const { children, className, node, ref, ...rest } = props
                const match = /language-(\w+)/.exec(className || "")
                return match ? (
                  <SyntaxHighlighter
                    {...rest}
                    ref={ref as LegacyRef<SyntaxHighlighter> | undefined}
                    PreTag="div"
                    children={String(children).replace(/\n$/, "")}
                    language={match[1]}
                    style={prism}
                  />
                ) : (
                  <code {...rest} className={className}>
                    {children}
                  </code>
                )
              },
            }}
          />
        </div>
        {!isBot && (
          <div className={styles.userIcon}>
            {accountUser && accountUser.photo ? (
              <img src={accountUser.photo} className={styles.userPhoto} />
            ) : (
              <Icon name="fa-solid fa-circle-user" size="2.4" />
            )}
          </div>
        )}
      </div>
    )
  }

  // ---------------------------------------------------------------------------
  return (
    <div className={styles.rightContentContainer}>
      <div className={styles.listWrapper}>
        {messages.map((message, index) => renderMessage(message, index))}

        {roomId && accountUser && typingMessage &&
          renderMessage({id: '', created_at: 0, roomId:roomId,  senderId: String(!accountUser.id), text: typingMessage }, -1)}
      </div>
      <DashboardInput
        value={userMessage}
        onValueChange={setUserMessage}
        onSend={() => {
          sendMessage()
          setUserMessage("")
        }}
        onEnter={() => {
          sendMessage()
          setUserMessage("")
        }}
        onSendVoice={sendVoiceMessage}
      />
    </div>
  )
}
 setMessages(finalUpdatedMessages)
      updateLocalMessages(finalUpdatedMessages, roomId!)
      setTypingMessage(null) - Argument of type '(MessageType | { id: string; created_at: number; roomId: string; senderId: boolean; text: string; })[]' is not assignable to parameter of type 'SetStateAction<MessageType[]>'.
  Type '(MessageType | { id: string; created_at: number; roomId: string; senderId: boolean; text: string; })[]' is not assignable to type 'MessageType[]'.
    Type 'MessageType | { id: string; created_at: number; roomId: string; senderId: boolean; text: string; }' is not assignable to type 'MessageType'.
      Type '{ id: string; created_at: number; roomId: string; senderId: boolean; text: string; }' is not assignable to type 'MessageType'.