import remarkGfm from "remark-gfm"
import ReactMarkdown from "react-markdown"
import { useParams } from "react-router-dom"
import { Config } from "../../../utils/config"
import styles from "./dashboard-message.module.css"
import botLogo from "../../../assets/images/bot-logo.svg"
import { MessageType } from "../../../types/message.type"
import { useAccountUser } from "../../../hooks/user.hook"
import { Icon } from "../../../ui-component/icon/icon.component"
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
import { prism } from "react-syntax-highlighter/dist/esm/styles/prism"
import { Loader } from "../../../ui-component/loader/loader.component"
import useWindowDimensions from "../../../hooks/window-dimensions.hook"
import { SidebarContext } from "../../side-bar-provider/side-bar.context"
import { useRef, useState, useEffect, LegacyRef, useContext } from "react"
import { DashboardInput } from "../dashboard-input/dashboard-input.component"
import { TokenUtils } from "../../../utils/token.utils"

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

  const { roomId } = useParams()
  const fetchedRef = useRef(false)

  const [text, setText] = useState("")
  const [skip, setSkip] = useState(0)
  const accountUser = useAccountUser()
  const { width: screenWidth } = useWindowDimensions()
  const [loading, setLoading] = useState<boolean>(false)
  const [isDisabled, setDisabled] = useState<boolean>(false)
  const messagesEndRef = useRef<HTMLDivElement | null>(null)
  const [messages, setMessages] = useState<MessageType[]>([])
  const { isSideBarOpen, setIsSideBarOpen } = useContext(SidebarContext)
  const [typingMessage, setTypingMessage] = useState<string | 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: "instant" })
    }
  }, [messages, typingMessage])

  // Fetch messages for the specific room when the component mounts or roomId changes
  useEffect(() => {
    setSkip(0)
    fetchedRef.current = false
    load()

    sendMessage(text)
  }, [roomId])

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

  async function load() {
    if (!accountUser || !roomId) return null

    try {
      setLoading(true)
      fetchedRef.current = true
      const responseMessage = await fetch(`${Config.url}/api/message/loading`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: "Bearer " + TokenUtils.get(),
        },
        body: JSON.stringify({
          skip: skip,
          roomId: roomId,
          senderId: accountUser.id,
        }),
        credentials: "include",
      })

      const loadMessages: MessageType[] = await responseMessage.json()

      setMessages(loadMessages)

      setLoading(false)
    } catch (error) {
      console.log("Something went wrong", error)
    }
  }

  async function addMessage(args: {
    text: string
    roomId: string
    senderId: string
  }): Promise<MessageType> {
    const sendMessage = {
      text: args.text,
      roomId: args.roomId,
      senderId: args.senderId,
    }

    const responseMessage = await fetch(`${Config.url}/api/message/add`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: "Bearer " + TokenUtils.get(),
      },
      body: JSON.stringify(sendMessage),
      credentials: "include",
    })

    return responseMessage.json()
  }

  async function sendMessage(messageText: string) {
    if (!accountUser || !roomId) return null
    setDisabled(true)

    let text: string

    const localMessageText = localStorage.getItem("newMessageText")

    if (localMessageText) {
      text = localMessageText.trim()
    } else {
      text = messageText.trim()
    }

    if (text) {
      let newMessage: MessageType = {
        id: "",
        text,
        roomId: roomId,
        created_at: Date.now(),
        senderId: accountUser.id,
      }

      newMessage = await addMessage({ ...newMessage })

      const updatedMessages = [...messages, newMessage]
      setMessages(updatedMessages)

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

      const reader = response.body && 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)
        }

        newMessage = await addMessage({
          text: botMessage,
          roomId: newMessage.roomId,
          senderId: "bot",
        })
        const finalUpdatedMessages: MessageType[] = [
          ...updatedMessages,
          newMessage,
        ]
        localStorage.removeItem("newMessageText")
        setMessages(finalUpdatedMessages)
        setTypingMessage(null)
      }
    }

    localStorage.removeItem("newMessageText")
    setText("")
    setDisabled(false)
  }

  function renderMessage(message: MessageType, index: number) {
    const isBot = message.senderId !== (accountUser && 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={botLogo} alt="logo" />
          </div>
        )}
        <div className={`${styles.chatMessage} ${styles.user}`}>
          <ReactMarkdown
            className={styles.messageText}
            remarkPlugins={[remarkGfm]}
            children={message.text.replace(/\n/g, "  \n")}
            components={{
              h1: ({ node, ...props }) => (
                <h1 className={styles.h1} {...props} />
              ),
              h2: ({ node, ...props }) => (
                <h2 className={styles.h2} {...props} />
              ),
              h3: ({ node, ...props }) => (
                <h3 className={styles.h3} {...props} />
              ),
              h4: ({ node, ...props }) => (
                <h4 className={styles.h4} {...props} />
              ),
              p: ({ node, ...props }) => <p className={styles.p} {...props} />,
              a: ({ node, ...props }) => <a className={styles.a} {...props} />,
              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>
                )
              },
              ul: ({ node, ...props }) => (
                <ul className={styles.ul} {...props} />
              ),
              ol: ({ node, ...props }) => (
                <ol className={styles.ol} {...props} />
              ),
              li: ({ node, ...props }) => (
                <li className={styles.li} {...props} />
              ),
              blockquote: ({ node, ...props }) => (
                <blockquote className={styles.blockquote} {...props} />
              ),
              img: ({ node, ...props }) => (
                <img className={styles.img} {...props} />
              ),
              hr: ({ node, ...props }) => (
                <hr className={styles.hr} {...props} />
              ),
            }}
          />
        </div>
        {!isBot && (
          <div className={styles.userIcon}>
            {accountUser && accountUser.photo ? (
              <img
                src={Config.imageUrl + accountUser.photo}
                className={styles.userPhoto}
              />
            ) : (
              <Icon name="fa-solid fa-circle-user" size="2.4" />
            )}
          </div>
        )}
      </div>
    )
  }

  // ---------------------------------------------------------------------------
  return (
    <div className={styles.rightContentContainer}>
      {loading ? (
        <Loader />
      ) : (
        <div className={styles.listWrapper}>
          {messages
            .sort((a, b) => a.created_at - b.created_at)
            .map((message, index) => renderMessage(message, index))}

          {roomId &&
            accountUser &&
            typingMessage &&
            renderMessage(
              {
                id: "",
                created_at: 0,
                roomId: roomId,
                senderId: "bot",
                text: typingMessage,
              },
              -1,
            )}
          <div ref={messagesEndRef} />
        </div>
      )}

      <DashboardInput
        text={text}
        resize
        placeHolder=""
        disabled={isDisabled}
        onTextChange={setText}
        onSend={(text: string) => {
          sendMessage(text)
          setText("")
        }}
      />
    </div>
  )
}
tell me about messagesEndRef