import useWindowDimensions from "../../../hooks/use-window-dimensions.hook"
import {
  useContext,
  useEffect,
  useState,
  useCallback,
  LegacyRef,
  useRef,
} 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 { 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"

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)

  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])

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

  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()) return

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

  // 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 = ""

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

  //             botMessage += decoder.decode(value, { stream: true })
  //             let index = 0

  //             while (index < botMessage.length) {
  //               setTypingMessage((current) =>
  //                 current ? current + botMessage[index] : botMessage[index],
  //               )
  //               index += 1
  //               await new Promise((resolve) => setTimeout(resolve, 10)) // Adjust delay as needed
  //             }
  //           }
  //           setMessages((prevMessages) => [
  //             ...prevMessages,
  //             { sender: "bot", text: botMessage },
  //           ])
  //           setTypingMessage(null)
  //         }

  //         setTypingMessage("")
  //         addCharacter()
  //       }

  //       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 = ""

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

  //             botMessage += decoder.decode(value, { stream: true })
  //             let index = 0

  //             while (index < botMessage.length) {
  //               setTypingMessage((current) =>
  //                 current ? current + botMessage[index] : botMessage[index],
  //               )
  //               index += 1
  //               await new Promise((resolve) => setTimeout(resolve, 10))
  //             }
  //           }
  //           setMessages((prevMessages) => [
  //             ...prevMessages,
  //             { sender: "bot", text: botMessage },
  //           ])
  //           setTypingMessage(null)
  //         }

  //         setTypingMessage("")
  //         addCharacter()
  //       }
  //     }
  //   },
  //   [userMessage],
  // )

  const handleItemClick = useCallback(async (itemText: string) => {
    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",
      },
      body: JSON.stringify({
        message: itemText,
      }),
      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)
    }
  }, [])

  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}
            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}>
            <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)}
        <div ref={messagesEndRef} />
        {messages.length === 0 && (
          <>
            <img src="../../../public/gpt.png" className={styles.image} />
            <div className={styles.actionsWrapper}>
              <DashboardPageAction
                label="今日の天気は？"
                icon="weather"
                onClick={() => handleItemClick("今日の天気は")}
              />
              <DashboardPageAction
                label="今日の生徒との雑談"
                icon="chat"
                onClick={() => handleItemClick("今日の生徒との雑談")}
              />
              <DashboardPageAction
                label="ニュースダイジェスト"
                icon="news"
                onClick={() => handleItemClick("今日のニュースダイジェスト")}
              />
            </div>
          </>
        )}
      </div>
      <DashboardInput
        value={userMessage}
        onValueChange={setUserMessage}
        onSend={() => {
          sendMessage()
          setUserMessage("")
        }}
        onEnter={() => {
          sendMessage()
          setUserMessage("")
        }}
        onSendVoice={sendVoiceMessage}
      />
    </div>
  )
}
why React markdown not rendering table ?