import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'

import {  objectToBase64 } from '../../qdn/encryption/group-encryption'
import { ChatList } from './ChatList'
import "@chatscope/chat-ui-kit-styles/dist/default/styles.min.css";
import Tiptap from './TipTap'
import { CustomButton } from '../../App-styles'
import CircularProgress from '@mui/material/CircularProgress';
import { Box, Input, Typography } from '@mui/material';
import { LoadingSnackbar } from '../Snackbar/LoadingSnackbar';
import { getNameInfo } from '../Group/Group';
import { Spacer } from '../../common/Spacer';
import { CustomizedSnackbars } from '../Snackbar/Snackbar';
import { getBaseApiReactSocket, isMobile, pauseAllQueues, resumeAllQueues } from '../../App';
import { getPublicKey } from '../../background';
import { useMessageQueue } from '../../MessageQueueContext';
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';




export const ChatDirect = ({ myAddress, isNewChat, selectedDirect, setSelectedDirect, setNewChat, getTimestampEnterChat, myName, balance, close}) => {
  const { queueChats, addToQueue, } = useMessageQueue();
    const [isFocusedParent, setIsFocusedParent] = useState(false);

  const [messages, setMessages] = useState([])
  const [isSending, setIsSending] = useState(false)
  const [directToValue, setDirectToValue] = useState('')
  const hasInitialized = useRef(false)
  const [isLoading, setIsLoading] = useState(false)
  const [openSnack, setOpenSnack] = React.useState(false);
  const [infoSnack, setInfoSnack] = React.useState(null);
  const [publicKeyOfRecipient, setPublicKeyOfRecipient] = React.useState("")
  const hasInitializedWebsocket = useRef(false)
  const editorRef = useRef(null);
  const socketRef = useRef(null);
  const timeoutIdRef = useRef(null);
  const groupSocketTimeoutRef = useRef(null);

  const setEditorRef = (editorInstance) => {
    editorRef.current = editorInstance;
  };
  const publicKeyOfRecipientRef = useRef(null)
   
  const getPublicKeyFunc = async (address)=> {
    try {
      const publicKey = await getPublicKey(address)
      if(publicKeyOfRecipientRef.current !== selectedDirect?.address) return
      setPublicKeyOfRecipient(publicKey)
    } catch (error) {
      
    }
  }

  const tempMessages = useMemo(()=> {
    if(!selectedDirect?.address) return []
    if(queueChats[selectedDirect?.address]){
      return queueChats[selectedDirect?.address]
    }
    return []
  }, [selectedDirect?.address, queueChats])
  useEffect(()=> {
    if(selectedDirect?.address){
      publicKeyOfRecipientRef.current = selectedDirect?.address
      getPublicKeyFunc(publicKeyOfRecipientRef.current)
    }
  }, [selectedDirect?.address])
 

  

    const decryptMessages = (encryptedMessages: any[])=> {
      try {
        return new Promise((res, rej)=> {
          chrome?.runtime?.sendMessage({ action: "decryptDirect", payload: {
            data: encryptedMessages,
            involvingAddress: selectedDirect?.address
        }}, (response) => {
        
            if (!response?.error) {
              res(response)
              if(hasInitialized.current){
          
                const formatted = response.map((item: any)=> {
                  return {
                    ...item,
                    id: item.signature,
                    text: item.message,
                    unread: item?.sender === myAddress ? false :  true
                  }
                } )
                setMessages((prev)=> [...prev, ...formatted])
              } else {
                const formatted = response.map((item: any)=> {
                  return {
                    ...item,
                    id: item.signature,
                    text: item.message,
                    unread: false
                  }
                } )
                setMessages(formatted)
                hasInitialized.current = true

              }
            }
            rej(response.error)
          });
        })  
      } catch (error) {
          
      }
    }

    const forceCloseWebSocket = () => {
      if (socketRef.current) {
        console.log('Force closing the WebSocket');
        clearTimeout(timeoutIdRef.current);
        clearTimeout(groupSocketTimeoutRef.current);
        socketRef.current.close(1000, 'forced');
        socketRef.current = null;
      }
    };
  
    const pingWebSocket = () => {
      try {
        if (socketRef.current?.readyState === WebSocket.OPEN) {
          socketRef.current.send('ping');
          timeoutIdRef.current = setTimeout(() => {
            if (socketRef.current) {
              socketRef.current.close();
              clearTimeout(groupSocketTimeoutRef.current);
            }
          }, 5000); // Close if no pong in 5 seconds
        }
      } catch (error) {
        console.error('Error during ping:', error);
      }
    };
  

    const initWebsocketMessageGroup = () => {
      forceCloseWebSocket(); // Close any existing connection
  
      if (!selectedDirect?.address || !myAddress) return;
  
      const socketLink = `${getBaseApiReactSocket()}/websockets/chat/messages?involving=${selectedDirect?.address}&involving=${myAddress}&encoding=BASE64&limit=100`;
      socketRef.current = new WebSocket(socketLink);
  
      socketRef.current.onopen = () => {
        console.log('WebSocket connection opened');
        setTimeout(pingWebSocket, 50); // Initial ping
      };
  
      socketRef.current.onmessage = (e) => {
        try {
          if (e.data === 'pong') {
            clearTimeout(timeoutIdRef.current);
            groupSocketTimeoutRef.current = setTimeout(pingWebSocket, 45000); // Ping every 45 seconds
          } else {
            decryptMessages(JSON.parse(e.data));
            setIsLoading(false);
          }
        } catch (error) {
          console.error('Error handling WebSocket message:', error);
        }
      };
  
      socketRef.current.onclose = (event) => {
        clearTimeout(groupSocketTimeoutRef.current);
        clearTimeout(timeoutIdRef.current);
        console.warn(`WebSocket closed: ${event.reason || 'unknown reason'}`);
        if (event.reason !== 'forced' && event.code !== 1000) {
          setTimeout(() => initWebsocketMessageGroup(), 10000); // Retry after 10 seconds
        }
      };
  
      socketRef.current.onerror = (error) => {
        console.error('WebSocket error:', error);
        clearTimeout(groupSocketTimeoutRef.current);
        clearTimeout(timeoutIdRef.current);
        if (socketRef.current) {
          socketRef.current.close();
        }
      };
    };

    const setDirectChatValueFunc = async (e)=> {
      setDirectToValue(e.detail.directToValue)
    }
    useEffect(() => {
      subscribeToEvent("setDirectToValueNewChat", setDirectChatValueFunc);
  
      return () => {
        unsubscribeFromEvent("setDirectToValueNewChat", setDirectChatValueFunc);
      };
    }, []);
  
    useEffect(() => {
      if (hasInitializedWebsocket.current || isNewChat) return;
      setIsLoading(true);
      initWebsocketMessageGroup();
      hasInitializedWebsocket.current = true;
  
      return () => {
        forceCloseWebSocket(); // Clean up WebSocket on component unmount
      };
    }, [selectedDirect?.address, myAddress, isNewChat]);



const sendChatDirect = async ({ chatReference = undefined, messageText}: any, address, publicKeyOfRecipient, isNewChatVar)=> {
  try {
    const directTo = isNewChatVar ? directToValue : address
 
    if(!directTo) return
    return new Promise((res, rej)=> {
      chrome?.runtime?.sendMessage({ action: "sendChatDirect", payload: {
        directTo,  chatReference, messageText, publicKeyOfRecipient, address: directTo
    }}, async (response) => {
    
        if (!response?.error) {
          if(isNewChatVar){
            
            let getRecipientName = null
            try {
              getRecipientName = await getNameInfo(response.recipient)
            } catch (error) {
              
            }
            setSelectedDirect({
              "address": response.recipient,
              "name": getRecipientName,
              "timestamp": Date.now(),
              "sender": myAddress,
              "senderName": myName
          })
          setNewChat(null)
          chrome?.runtime?.sendMessage({
            action: "addTimestampEnterChat",
            payload: {
              timestamp: Date.now(),
              groupId: response.recipient,
            },
          });
          setTimeout(() => {
            getTimestampEnterChat()
          }, 400);
          }
          res(response)
          return
        }
        rej(response.error)
      });
    })  
  } catch (error) {
      throw new Error(error)
  } finally {
  }
}
const clearEditorContent = () => {
  if (editorRef.current) {
    editorRef.current.chain().focus().clearContent().run();
    if(isMobile){
      setTimeout(() => {
        editorRef.current?.chain().blur().run(); 
        setIsFocusedParent(false)
        executeEvent("sent-new-message-group", {})
      }, 200);
    }
  }
};


    const sendMessage = async ()=> {
      try {
        if(+balance < 4) throw new Error('You need at least 4 QORT to send a message')
        if(isSending) return
        if (editorRef.current) {
          const htmlContent = editorRef.current.getHTML();
     
          if(!htmlContent?.trim() || htmlContent?.trim() === '<p></p>') return
          setIsSending(true)
          pauseAllQueues()
        const message = JSON.stringify(htmlContent)
       
      
        if(isNewChat){
          await sendChatDirect({ messageText: htmlContent}, null, null, true)
          return
        }
        const sendMessageFunc = async () => {
          await sendChatDirect({ messageText: htmlContent}, selectedDirect?.address, publicKeyOfRecipient, false)
        };
  
        // Add the function to the queue
        const messageObj = {
          message: {
            text: htmlContent,
            timestamp: Date.now(),
          senderName: myName,
          sender: myAddress
          },
         
        }
        addToQueue(sendMessageFunc, messageObj, 'chat-direct',
        selectedDirect?.address );
        setTimeout(() => {
          executeEvent("sent-new-message-group", {})
        }, 150);
        clearEditorContent()
        }
        // send chat message
      } catch (error) {
        const errorMsg = error?.message || error
        setInfoSnack({
          type: "error",
          message: errorMsg === 'invalid signature' ? 'You need at least 4 QORT to send a message' :  errorMsg,
        });
        setOpenSnack(true);
        console.error(error)
      } finally {
        setIsSending(false)
        resumeAllQueues()
      }
    }


    
  return (
    <div style={{
      height: isMobile ? '100%' : '100vh',
      display: 'flex',
      flexDirection: 'column',
      width: '100%'
    }}>
        <Box onClick={close} sx={{
              display: 'flex',
              alignItems: 'center',
              gap: '5px',
              cursor: 'pointer',
              padding: '4px 6px',
              width: 'fit-content',
              borderRadius: '3px',
              background: 'rgb(35, 36, 40)',
              margin: '10px 0px',
              alignSelf: 'center'
            }}>
              <ArrowBackIcon sx={{
                color: 'white',
                fontSize: isMobile ? '20px' : '20px'
              }}/>
              <Typography sx={{
                color: 'white',
                fontSize: isMobile ? '14px' : '14px'
              }}>Close Direct Chat</Typography>
            </Box>
      {isNewChat && (
        <>
        <Spacer height="30px" />
                <Input sx={{
                  fontSize: '18px',
                  padding: '5px'
                }} placeholder='Name or address' value={directToValue} onChange={(e)=> setDirectToValue(e.target.value)} />

        </>
      )}
      
              <ChatList initialMessages={messages} myAddress={myAddress} tempMessages={tempMessages}/>

   
      <div style={{
        // position: 'fixed',
        // bottom: '0px',
        backgroundColor: "#232428",
        minHeight: isMobile ? '0px' : '150px',
        maxHeight: isMobile ? 'auto' : '400px',
        display: 'flex',
        flexDirection: 'column',
        overflow: 'hidden',
        width: '100%',
        boxSizing: 'border-box',
        padding: isMobile ? '10px' : '20px',
        position: isFocusedParent ? 'fixed' : 'relative',
        bottom: isFocusedParent ? '0px' : 'unset',
        top: isFocusedParent ? '0px' : 'unset',
        zIndex: isFocusedParent ? 5 : 'unset'
      }}>
      <div style={{
            display: 'flex',
            flexDirection: 'column',
            flexGrow: isMobile && 1,
            overflow: !isMobile &&  "auto",
      }}>

     
      <Tiptap isFocusedParent={isFocusedParent} setEditorRef={setEditorRef} onEnter={sendMessage} isChat disableEnter={isMobile ? true : false} setIsFocusedParent={setIsFocusedParent}/>
      </div>
      <Box sx={{
        display: 'flex',
        width: '100&',
        gap: '10px',
        justifyContent: 'center',
        flexShrink: 0,
        position: 'relative',
      }}>
         {isFocusedParent && (
               <CustomButton
               onClick={()=> {
                 if(isSending) return
                 setIsFocusedParent(false)
                 clearEditorContent()
                 // Unfocus the editor
               }}
               style={{
                 marginTop: 'auto',
                 alignSelf: 'center',
                 cursor: isSending ? 'default' : 'pointer',
                 background: 'red',
                 flexShrink: 0,
                 padding: isMobile && '5px'
               }}
             >
               
               {` Close`}
             </CustomButton>
           
            )}
      <CustomButton
              onClick={()=> {
                if(isSending) return
                sendMessage()
              }}
              style={{
                marginTop: 'auto',
                alignSelf: 'center',
                cursor: isSending ? 'default' : 'pointer',
                background: isSending && 'rgba(0, 0, 0, 0.8)',
                flexShrink: 0,
                padding: isMobile && '5px'
              }}
            >
              {isSending && (
                <CircularProgress
                size={18}
                sx={{
                  position: 'absolute',
                  top: '50%',
                  left: '50%',
                  marginTop: '-12px',
                  marginLeft: '-12px',
                  color: 'white'
                }}
              />
              )}
              {` Send`}
            </CustomButton>
           
              </Box>
      </div>
      <LoadingSnackbar open={isLoading} info={{
        message: "Loading chat... please wait."
      }} />
       <CustomizedSnackbars open={openSnack} setOpen={setOpenSnack} info={infoSnack} setInfo={setInfoSnack}  />
    </div>
  )
}
