import { useContext, useEffect, useState, useCallback, LegacyRef } from "react"
import useWindowDimensions from "../../../hooks/use-window-dimensions"
import { SidebarContext } from "../../side-bar-provider/side-bar.context"
import { DashboardInput } from "../dashboard-input/dashboard-input.component"
import { DashboardPageAction } from "../dashboard-page-action/dashboard-page-action.component"
import styles from "./dashboard-message.module.css"
import ReactMarkdown from "react-markdown"
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"
import {
  prism,
} from "react-syntax-highlighter/dist/esm/styles/prism"

import { Icon } from "../../../ui-component/icon/icon.component"
import { Config } from "../../../utils/config"

type Message = {
  sender: string
  text: string
}

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

  const { width: screenWidth } = useWindowDimensions()
  const { isSideBarOpen, setIsSideBarOpen } = useContext(SidebarContext)

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

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

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

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

  const handleSend = useCallback(
    async (file?: File) => {
      const userIdString = localStorage.getItem("currentUser")
      const userIdObject = userIdString ? JSON.parse(userIdString) : null
      const userId = userIdObject ? userIdObject.id : null
      if (!userMessage.trim() && !file) return

      if (userMessage.trim()) {
        const newMessage: Message = { sender: "user", text: userMessage }
        setMessages((prevMessages) => [...prevMessages, newMessage])

        const response = await fetch(`${Config.url}/api/gptTeacher/message`, {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            "user-id": userId as string,
          },
          body: JSON.stringify({
            message: userMessage,
          }),
          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)
        }

        setUserMessage("")
      } else if (file) {
        const formData = new FormData()
        formData.append("file", file)

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

        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)
        }
      }
    },
    [userMessage],
  )

  const handleItemClick = useCallback(async (itemText: string) => {
    const userIdString = localStorage.getItem("currentUser")
    const userIdObject = userIdString ? JSON.parse(userIdString) : null
    const userId = userIdObject ? userIdObject.id : null

    const newMessage: Message = { sender: "user", text: itemText }
    setMessages((prevMessages) => [...prevMessages, newMessage])

    const response = await fetch(`${Config.url}/api/gptTeacher/message`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "user-id": userId as string,
      },
      body: JSON.stringify({
        message: itemText,
      }),
    })

    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)
    }
  }, [])

  function renderMessage(message: Message, index: number) {
    const isBot = message.sender === "bot"
    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[message.sender]}`}>
          <ReactMarkdown
            className={styles.messageText}
            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>
                )
              },
            }}
          >
            {message.text}
          </ReactMarkdown>
        </div>
        {!isBot && (
          <div className={styles.userIcon}>
            <Icon name="fa-solid fa-circle-user" size="2.4" />
          </div>
        )}
      </div>
    )
  }

  return (
    <div className={styles.rightContentContainer}>
      <div
        className={
          messages.length === 0 ? styles.emptyListWrapper : styles.listWrapper
        }
      >
        {messages.map((message, index) => renderMessage(message, index))}
        {typingMessage &&
          renderMessage({ sender: "bot", text: typingMessage }, -1)}
        {messages.length === 0 && (
          <>
            <img src="../../../public/gpt.png" className={styles.image} />
            <div className={styles.actionsWrapper}>
              <DashboardPageAction
                label="今日の天気は？"
                icon="weather"
                onClick={() =>
                  handleItemClick("Can you help me with this issue?")
                }
              />
              <DashboardPageAction
                label="今日の生徒との雑談"
                icon="chat"
                onClick={() =>
                  handleItemClick("I need assistance with my account.")
                }
              />
              <DashboardPageAction
                label="ニュースダイジェスト"
                icon="news"
                onClick={() => handleItemClick("Please explain this feature.")}
              />
            </div>
          </>
        )}
      </div>
      <DashboardInput
        value={userMessage}
        onValueChange={setUserMessage}
        onSend={() => {
          handleSend()
          setUserMessage("")
        }}
        onEnter={() => {
          handleSend()
          setUserMessage("")
        }}
      />
    </div>
  )
}
i want bot generate text like chatgpt generate one by one then scroll it. How to implement it ?