"use client"
import React, { useEffect, useRef, useState } from "react";
import ConversationFrontend from "../components/ConversationFrontend";
import InputFrontend from "../components/InputFrontend";
import VoiceSend from "./voice_backend"
import axios from "axios";
import { skip } from "node:test";


const InputOutputBackend: React.FC = () => {
  type Message = {
    role: string
    content: string
  }

  const [accessToken, setAccessToken] = useState("")
  const postWorkerRef = useRef<Worker | null>(null)
  const getWorkerRef = useRef<Worker | null>(null)
  const [messages, setMessages] = useState<Message[]>([{ role: "assistant", content: "Hello! How can I help you?" }])
  const [liveMessage, setLiveMessage] = useState("")
  const [inputMessage, setInputMessage] = useState<string>("")
  const [inputDisabled, setInputDisabled] = useState(false)
  const [lastMessage, setLastMessage] = useState<Message>({ role: "user", content: "Not supposed to happen." })
  const [isRecording, setIsRecording] = useState(false);
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const audioChunksRef = useRef<Blob[]>([]);


  console.log(messages);


  useEffect(() => {
    getNewToken()

    postWorkerRef.current = new Worker(new URL("./threads/PostWorker.js", import.meta.url))

    postWorkerRef.current.onmessage = (event) => {
      const status = event.data.status
      if (status == 200) {
        setInputDisabled(false)
        endGetWorker()
      } else if (status == 500) {
        setInputDisabled(false)
        if (getWorkerRef.current) {
          addMessage("assistant", "There was an Error with the AI response")
          getWorkerRef.current.postMessage("terminate")
          getWorkerRef.current.terminate()
        }
      }
    }

    return () => {
      if (postWorkerRef.current) {
        postWorkerRef.current.terminate()
      }
      if (getWorkerRef.current) {
        getWorkerRef.current.postMessage("terminate")
        getWorkerRef.current.terminate()
      }
    }
  }, [])

  const getNewToken = () => {
    console.log("getting access");
    axios.get("http://localhost:5000/interstellar_ai/api/ai_create")
      .then(response => {
        setAccessToken(response.data.access_token)
        console.log(response.data.access_token);
      })
      .catch(error => {
        console.log("error:", error.message);

      })
  }

  const startGetWorker = () => {
    if (!getWorkerRef.current) {
      getWorkerRef.current = new Worker(new URL("./threads/GetWorker.js", import.meta.url))

      getWorkerRef.current.postMessage({ action: "start", access_token: accessToken })

      addMessage("assistant", "")
      getWorkerRef.current.onmessage = (event) => {
        const data = event.data

        if (event.data == "error") {
          setLiveMessage("error getting AI response: " + data.error)
        } else {
          console.log("Received data:", data);
          editLastMessage(data.response)
        }
      }

      getWorkerRef.current.onerror = (error) => {
        console.error("Worker error:", error)
      }
    }
  }

  const endGetWorker = () => {
    if (getWorkerRef.current) {
      getWorkerRef.current.postMessage({ action: "terminate" })
      getWorkerRef.current.terminate()
      getWorkerRef.current = null
      console.log(messages);
    }
  }

  const editLastMessage = (newContent: string) => {
    if (newContent == "") {
      newContent = "Generating answer..."
    }
    setMessages((prevMessages) => {
      const updatedMessages = prevMessages.slice(); // Create a shallow copy of the current messages
      if (updatedMessages.length > 0) {
        const lastMessage = updatedMessages[updatedMessages.length - 1];
        updatedMessages[updatedMessages.length - 1] = {
          ...lastMessage, // Keep the existing role and other properties
          content: newContent, // Update only the content
        };
      }
      return updatedMessages; // Return the updated array
    });
  };


  const addMessage = (role: string, content: string) => {
    setMessages(previous => [...previous, { role, content }])
  }
  const handleSendClick = (inputValue: string, override: boolean) => {
    if (inputValue != "") {
      console.log(inputDisabled)
      if (!inputDisabled || override) {
        setInputDisabled(true)
        if (postWorkerRef.current) {
          addMessage("user", inputValue)
          console.log("input:", inputValue);
          postWorkerRef.current.postMessage({ messages: [...messages, { role: "user", content: inputValue }], ai_model: "phi3.5", access_token: accessToken })
          startGetWorker()
        }
      }
    }
  }

  const startRecording = async () => {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    mediaRecorderRef.current = new MediaRecorder(stream);

    mediaRecorderRef.current.ondataavailable = (event) => {
      audioChunksRef.current.push(event.data);
    };

    mediaRecorderRef.current.onstop = () => {
      const audioBlob = new Blob(audioChunksRef.current, { type: 'audio/wav' });
      audioChunksRef.current = []; // Clear the chunks for the next recording
      // Call your existing function to send the audioBlob
      // Example: sendAudioToApi(audioBlob);
    };

    mediaRecorderRef.current.start();
    setIsRecording(true);

    // Automatically stop recording after 10 seconds
    setTimeout(() => {
      stopRecording();
    }, 10000);
  };

  const stopRecording = () => {
    if (mediaRecorderRef.current) {
      mediaRecorderRef.current.stop();
      setIsRecording(false);
      var remote = new VoiceSend()
      remote.sendToVoiceRecognition(new Blob(audioChunksRef.current, { type: 'audio/wav' }), remote.voiceDataTemplate);
    }
  };


  const handleMicClick = () => {
    if (!isRecording) {
      startRecording();
    } else {
      stopRecording();
    }
  };

  const handleResendClick = () => {
    var temporary_message = messages[messages.length - 2]['content']
    const updatedMessages = messages.slice(0, -2)
    setMessages(updatedMessages)
    endGetWorker()
    getNewToken()
    setInputDisabled(false)
    handleSendClick(temporary_message, true)
  }

  const handleEditClick = () => {
    setInputMessage(messages[messages.length - 2]['content'])
    const updatedMessages = messages.slice(0, -2)
    setMessages(updatedMessages)
    endGetWorker()
    getNewToken()
    setInputDisabled(false)
  }

  const handleCopyClick = async () => {
    try {
      await navigator.clipboard.writeText(messages[messages.length - 1]['content']);
    } catch (err) {
      console.error('Failed to copy: ', err);
    }
  }

  return (
    <div>
      <ConversationFrontend
        messages={messages}
        onResendClick={handleResendClick}
        onEditClick={handleEditClick}
        onCopyClick={handleCopyClick}
      />
      <InputFrontend
        message={inputMessage}
        onSendClick={handleSendClick}
        onMicClick={handleMicClick}
        inputDisabled={inputDisabled}
      />
    </div>
  )
}

export default InputOutputBackend





