import { invoke } from '@tauri-apps/api/core';
import { useEffect, useRef, useState } from "react";
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';

import { Countdown } from "../comps/timer";

import { Status, useChat } from "../util/useChat";
import { getSummary } from "../util/chat";
import { saveHistory } from "../util/output";
import NumPad, { NUMPAD_TYPE } from "../comps/numpad";
import { Light } from "../comps/light";
import { useData } from "../util/useData";
import VoiceAnalysis from "../comps/voiceanalysis";
import { sendOsc, OSC_ADDRESS, updatePrompt, onOscMessageReceived, sendOscStatus } from "../util/osc";
import { DebugControl, TEST_PROMPT } from "../comps/debug";
import { useUser } from "../util/useUser";


const CUELIST_FILE = 'cuelist_0923.json';
const AUDIO_FADE_TIME=3000; // in ms

const EmojiType={
    phone: '📞',
    headphone: '🎧',
    speaker: '🔊',
    chat: '🤖',
    chat_end: '🤖',
    user_input: '💬',
    announce: '📢',
}

const ChatStatus={
    System: 'system',
    User: 'user',
    Processing: 'processing',
    Clear: 'clear',
    End: 'end',
    Playing: 'playing',
    Message: 'message', 
}

const Voice={
    ONYX: 'onyx',
    SHIMMER: 'shimmer',
}

export function FreeFlow(){

    const { data }=useData();

    const [cuelist, setCuelist] = useState([]);
    const [currentCue, setCurrentCue] = useState(null);
    const [nextCue, setNextCue] = useState(null);
    const [localIP, setLocalIP] = useState(null);

    const [chatWelcome, setChatWelcome] = useState(null);
    const [audioInput, setAudioInput] = useState(true); 
    const [autoSend, setAutoSend] = useState(true);
    const [chatStatus, setChatStatus] = useState(ChatStatus.System); // System, User, Processing

    const [padInput, setPadInput] = useState(null);

    const [inputReady, setInputReady] = useState(false);

    const { userId, setUserId, getFileId, setPassword, reset:resetUser, uploadHistory, setSummary, summary,setChoice,choice, getUploadFolder,getDataId, writeSheet } = useUser();

    const refTimer=useRef();
    const refAudio=useRef();
    const refAudioPrompt=useRef();

    const refAudioAnnounce=useRef();

    const refInput=useRef();
    // const refLight=useRef();

    const refPauseTimer=useRef();
    const refSpeechPaused=useRef(false);
    const refChatCueEnd=useRef(false);

    const refContainer=useRef(); 

    const refCurrentCue= useRef(null);
    const refData=useRef(data);

    const refHintTimeout=useRef();
    const refInputTimeout=useRef();

    const refFadeOutInterval=useRef();
    const refVolDownInterval=useRef();

    const [lastOsc, setLastOsc]=useState();

    const { history, status, reset, sendMessage, setStatus, audioOutput, setAudioOutput, stop:stopChat, 
            audioUrl }=useChat();
    
    
    const {
        transcript,
        finalTranscript,
        listening,
        resetTranscript,
        browserSupportsSpeechRecognition,
        isMicrophoneAvailable,
      }=useSpeechRecognition();
    
    
    function resetData() {
        setSummary(null);
      
        reset();
        resetUser();
        sendOsc(OSC_ADDRESS.CHOICE, 'reset');
        sendOsc(OSC_ADDRESS.SPEECH, 'stop');

        setPadInput();
        setChoice();
    }

    function onOsc(payload){
        console.log('onOsc', payload);
        const address=payload.addr;
        const message=payload.args[0];
        const params=message.split('#');

        if(params[0]!='all'){
            console.log('set lastOsc', {address, params});
            setLastOsc(()=>({address, params}));
            return;
        }

        switch(address){
            case OSC_ADDRESS.PLAY_CUE:                
                    setNextCue(()=>params[1]);
                break;
            case OSC_ADDRESS.STOP_CUE:
                onStop();
                break;
            case OSC_ADDRESS.RESET_CUE:
                sendOsc(OSC_ADDRESS.STATUS, 'reset');
                onStop();
                resetData();
                break;            
        }

        // Handle OSC messages here
    }

    function sendPrompt(){
        // send prompt
        let raw_prompt=history[history.length-1]?.prompt || '';

        if(raw_prompt && raw_prompt.trim() !== '') {
            const prompt = `${data?.sd_prompt_prefix || ''}${raw_prompt}${data?.sd_prompt_suffix || ''}`;

            updatePrompt(prompt);
            sendOsc(OSC_ADDRESS.PROMPT, prompt);
            // play audio for prompt
            refAudioPrompt.current?.play().catch(error => {
                console.error("Audio prompt playback error:", error);
            });

            refAudioPrompt.current.onended = () => {
                console.log('Audio prompt ended, setting chat status to User');
                setChatStatus(ChatStatus.User); // Set chat status to User after audio ends

                const user_input = history.find(msg => msg.role === 'user');
                if(user_input && user_input.content.trim() !== '') {
                    sendOsc(OSC_ADDRESS.STATUS, 'go'); // Send OSC status message
                }

            }

        }else{
            setChatStatus(()=>ChatStatus.User); // Reset chat status to User after audio ends
        }

    }


    function playAudio(url){
        if(!url) return;

        console.log('Playing audio:', url);        

        if(refCurrentCue.current?.layer=='announce'){
            if(refAudioAnnounce.current) {
                refAudioAnnounce.current.pause(); // Stop any currently playing announce audio
            }
            refAudioAnnounce.current = new Audio(url);
            refAudioAnnounce.current.loop=refCurrentCue.current?.loop || false; // Set loop if defined in cue
            refAudioAnnounce.current.play().catch(error => {
                console.error("Audio announce playback error:", error);
            });


            // lower audio
            if(refAudio.current) {
                // fade out current audio
                if(refVolDownInterval.current){
                    clearInterval(refVolDownInterval.current);
                }

                const dest=0.3;
                let fadeOutInterval = setInterval(() => {
                   if (refAudio.current.volume > dest) {
                        refAudio.current.volume =Math.max(dest,  refAudio.current.volume - 1.0/(AUDIO_FADE_TIME/100)); // Decrease volume gradually
                    } else {
                        clearInterval(fadeOutInterval);
                    }
                }, 100);
                refVolDownInterval.current=fadeOutInterval;
            }

            return;
        }


        if(refAudioAnnounce.current) {
            refAudioAnnounce.current.pause(); // Stop any currently playing announce audio
            refAudioAnnounce.current = null;
        }

        if(refAudio.current) {
            refAudio.current.pause(); // Stop any currently playing audio
        }

        let audioUrl = url;
        // if(voice==Voice.SHIMMER) audioUrl = url.replace(Voice.ONYX, Voice.SHIMMER);
        // console.log('Using voice:', voice, 'for audio:', audioUrl);

        const audio = new Audio(audioUrl);
        

        //TODO: if cue end, don't play audio
        if(refCurrentCue.current?.type=='chat'){
            // if(refChatCueEnd.current) {
            //     console.log('Chat cue has ended, not playing audio:', url);
            //     setChatStatus(ChatStatus.Clear); // Reset chat status to Clear
            //     onCueEnd();
            //     return;
            // }
        }


        audio.loop=refCurrentCue.current?.loop || false; // Set loop if defined in cue
        

        audio.addEventListener("loadedmetadata", () => {
            if(refCurrentCue.current?.type!='chat' && refCurrentCue.current?.type!='user_input') {
                refTimer.current?.restart(audio.duration*1000 || 0);
                audio.play().catch(error => {
                    console.error("Audio playback error:", error);            
                });

            }else{
                if(refCurrentCue.current?.type=='chat'){
                    
                    if(refTimer.current?.remainingTime < audio.duration*1000) {
                        console.log('Audio duration is longer than remaining cue time, not playing audio:', url);
                        // send propmpt
                        sendPrompt();
                        return;
                    }else{
                        setChatStatus(()=>ChatStatus.System);
                        audio.play().catch(error => {
                            console.error("Audio playback error:", error);
                        });
                    }
                    
                }else{
                    setChatStatus(()=>ChatStatus.Playing);

                    audio.play().catch(error => {
                        console.error("Audio playback error:", error);            
                    });

                }
            }
        });

        audio.onended = () => {
            if(refCurrentCue.current?.type!='chat'){
                setChatStatus(ChatStatus.End);
                onCueEnd();
                console.log('Audio ended, ending current cue');
            }else{                              

                // if history contains user input, send it
               
                sendPrompt();
                
            }
        }

        refAudio.current = audio; // Store the new audio reference
        
    }
    function fadeOutAudio(callback){

        if(refVolDownInterval.current) clearInterval(refVolDownInterval.current);

        if(refAudio.current || refAudioAnnounce.current){
            console.log('Fading out audio');

            let audio = refAudio.current;
            let announce = refAudioAnnounce.current;

            if(refFadeOutInterval.current){
                clearInterval(refFadeOutInterval.current);
                refFadeOutInterval.current=null;
            }

            let fadeOutInterval = setInterval(() => {
                if(audio){
                    if (audio.volume > 0) {
                        audio.volume =Math.max(0,  audio.volume - 1.0/(AUDIO_FADE_TIME/100)); // Decrease volume gradually
                    } else {
                        audio.pause();
                        audio.volume = 0; // Reset volume for next play
                        
                    }
                }                

                if(announce){
                    if (announce.volume > 0) {
                        announce.volume = Math.max(0, announce.volume - 1.0/(AUDIO_FADE_TIME/100)); // Decrease volume gradually
                    } else {
                        //clearInterval(fadeOutInterval);
                        announce.pause();
                        announce.volume = 0; // Reset volume for next play                    
                    }
                }

                if((audio==null || audio.volume==0) && (announce==null || announce.volume==0)){
                    clearInterval(fadeOutInterval);
                    if(callback) callback();
                }
            }, 100); // Decrease volume every 100ms 
            
            refFadeOutInterval.current=fadeOutInterval;

        }else{
            if(callback) callback();
        }
    }

    function playCue(cue) {

        if(!cue) return;
        console.log('Playing cue:', cue);
        
        // stop audio
        // if(refAudio.current) refAudio.current.pause();

        
        
        setCurrentCue(cue);
        refCurrentCue.current = cue; // Store the current cue in ref
       


        if(parseFloat(cue.id)<=4.2){
            // Special case for starting a conversation
            console.log('clear conversation...');
            reset(); 

            const prompt = `${data?.sd_prompt_prefix || ''}${TEST_PROMPT}${data?.sd_prompt_suffix || ''}`;
            updatePrompt(prompt);    
        }

      
        // clear unity hint
        if(refHintTimeout.current) clearTimeout(refHintTimeout.current);
            
        sendOsc(OSC_ADDRESS.HINT, ''); // Clear hint message
        sendOsc(OSC_ADDRESS.INPUT, ''); // Clear input message
        sendOsc(OSC_ADDRESS.SPEECH, 'stop');

        setPadInput();

        switch(cue.type){
            case 'chat':
                // Special case for starting a conversation
                refChatCueEnd.current=false;
                resetTranscript();
                console.log('Starting conversation...');
                setChatStatus(ChatStatus.User);
                //sendMessage(null, false, false, null); // Send initial message with voice      
                //setChatWelcome(true);               
                //resetData(); // Reset data for new conversation  
                break;   
            
            case 'summary':
                console.log('Getting summary...');

                setChatStatus(ChatStatus.Clear); // Set chat status to Processing
                
                let message=refInput.current?.value?.trim() || history.map(el=>`${el.role}:${el.content}`).join('\n');
                console.log('Summary input message:', message);

                if(!message || message.length==0) {

                    setSummary();
                    console.log('no message input, clear summary');
                    onCueEnd(); // End the current cue after getting summary

                }else{

                    getSummary(message, data).then(summary_ => {

                        console.log('Summary:', summary_);
                        onCueEnd(); // End the current cue after getting summary

                        setSummary(()=>summary_?.result);
                        refContainer.current.scrollTop = refContainer.current.scrollHeight; // Scroll to bottom
                
                    }).catch(error => {
                        console.error('Error getting summary:', error);
                    });
                }
                
                
                break;
            case 'user_input':
                setChatStatus(ChatStatus.Message); // Set chat status to User
                resetTranscript(); // Reset transcript for user input
                break;
            default:
                setChatStatus(ChatStatus.Clear);
                break;
        }

        
        // if(cue.callback=='fade_in_light') refLight.current.fadeIn(); // Fade in light for conversation start
        // if(cue.callback=='fade_out_light') refLight.current.fadeOut(); // Fade out light for conversation end

        if(cue.hint!=null && cue.hint_time!=null){
            refHintTimeout.current=setTimeout(()=>{
                sendOsc(OSC_ADDRESS.HINT, cue.hint); // Send OSC hint message
                
            }, cue.hint_time);
        }

        setInputReady(false);
            
        if(cue.input_time!=null){
            if(refInputTimeout.current) clearTimeout(refInputTimeout.current);
            refInputTimeout.current=setTimeout(()=>{
                setInputReady(()=>true);
            }, cue.input_time);
        }

        if(cue.audioFile){            
            playAudio(cue.audioFile);
        }
        
        if(cue.duration){
            refTimer.current.restart(cue.duration*1000, ()=>{
                onCueEnd(cue);
            });
        }

        switch(cue.callback){
            case 'exportFile':
                exportFile();
                break;
            // case 'fadeout':
            //     fadeOutAudio();
            //     break;
        }


        // control unity
        if(cue.status && cue.status!='go') {
            if(cue.status_delay) {
                setTimeout(()=>{
                    sendOsc(OSC_ADDRESS.STATUS, cue.status); // Send OSC status message
                }, cue.status_delay);
            }else{
                sendOsc(OSC_ADDRESS.STATUS, cue.status); // Send OSC status message
            }
            if(cue.status=='reset') {
                // refLight.current.set(1);
                resetData();
            }
        }
        if(cue.type=='chat' || cue.type=='user_input') {
            sendOsc(OSC_ADDRESS.COUNTDOWN, cue.duration || '0'); // Send OSC countdown message
        }else{
            sendOsc(OSC_ADDRESS.COUNTDOWN, '0'); // Reset countdown for non-chat cues
        }
        if(cue.numpad_type=='choice'){
            setChoice();
        }

        sendOscStatus(OSC_ADDRESS.CLIENT_STATUS,`${data.id}#playcue#${cue.id}`);

        console.log('~~~~ clear pause timer');
        if(refPauseTimer.current) clearTimeout(refPauseTimer.current);
        // refSpeechPaused.current=false;
    }

    function onCueEnd() {
        
        refTimer.current?.stop(); // Stop the timer when cue ends
        
        if(!refCurrentCue.current) return;
        const cue= refCurrentCue.current; // Get the current cue from ref

        if(cue.type=='chat'){
            // if(chatStatus==ChatStatus.System) {
            //     console.log('Still talking...');
            //     refChatCueEnd.current=true;
            //     return;
            // }
            console.log('save chat history:', history);
            uploadHistory(history); // Save chat history when cue ends
        }
      

       
        sendOsc(OSC_ADDRESS.HINT, ''); // Clear hint message
        
        sendOsc(OSC_ADDRESS.SPEECH, 'stop');

        if(cue.numpad_type=='choice'){
            if(!choice){
                console.log('set default choice to save');
                setChoice('save');
                sendOsc(OSC_ADDRESS.CHOICE, 'save'); // Send OSC save choice message
            }else{
               // sendOsc(OSC_ADDRESS.CHOICE, choice); // Send OSC save choice message                
            }
        }

        refAudio.current?.pause(); // Pause any playing audio
        console.log('onCueEnd:', cue.id);

        
        resetTranscript(); // Reset transcript after cue ends
        sendOscStatus(OSC_ADDRESS.CLIENT_STATUS, `${data.id}#endcue#${cue.id}`);

        if(cue.auto || cue.callback=='numpad'){
            playCue(cuelist.find(c => c.id === cue.nextcue));
        }
        
    }

    function onStop(){
        console.log('Stopping current cue');
        if(refAudio.current) {
            refAudio.current.pause();
            refAudio.current = null;
        }
        if(refAudioAnnounce.current) {
            refAudioAnnounce.current.pause();
            refAudioAnnounce.current = null;
        }
        
        setCurrentCue(null);
        refCurrentCue.current = null; // Clear the current cue reference
        
        refTimer.current.restart(0);

        stopChat(); // Stop chat processing
    }


    function onNumpad(mess){
        console.log('onNumPad',mess);
       setPadInput(()=>mess);
    }

    function exportFile(){
        const user_input = history.find(msg => msg.role === 'user');
        const default_image=!(user_input && user_input.content.trim() !== '');

        sendOsc(OSC_ADDRESS.EXPORT, `${getUploadFolder()}#${getDataId()}#${summary||''}#${getFileId(padInput)}#${choice||''}#${default_image?'default':'generated'}`); // Send OSC export message
        writeSheet();
    }

    useEffect(()=>{

        if(!lastOsc) return;
            console.log('Process last OSC:', lastOsc);

        if(lastOsc.params[0]!=data.id) return;

        switch(lastOsc.address){
            case OSC_ADDRESS.PLAY_CUE:
                setNextCue(()=>lastOsc.params[1]);
                break;
            case OSC_ADDRESS.STOP_CUE:
                onStop();
                break;
            case OSC_ADDRESS.RESET_CUE:
                sendOsc(OSC_ADDRESS.STATUS, 'reset');
                onStop();
                resetData();
                break;
        }

    },[lastOsc]);

    useEffect(()=>{


        if(padInput==null) return;

        console.log('Numpad input:', padInput);        
        if(refCurrentCue.current?.callback!='numpad') return;        
        
        let cue=refCurrentCue.current;
        let next=cue.nextcue;
        switch(cue.numpad_type){
            case NUMPAD_TYPE.USERID:
                console.log('set id', padInput);
                setUserId(()=>padInput);
                break;
            case NUMPAD_TYPE.CHOICE:
                next=cue.branch[padInput.toString()].nextcue;          
                setChoice(()=>cue.branch[padInput.toString()].description); // Set choice for user input      
                sendOsc(OSC_ADDRESS.CHOICE, cue.branch[padInput.toString()].description);       
                break;
            case NUMPAD_TYPE.PASSWORD:
                setPassword(padInput);                
                // sendOsc(OSC_ADDRESS.PASSWORD, mess); // Send OSC password message
                // sendOsc(OSC_ADDRESS.CHOICE, choice); // Send OSC save choice message
                break;
        }
                
        if(next){
           onStop();
            console.log('Finish enter number, next cue:', next);
            playCue(cuelist.find(c => c.id === next));
        }


    },[padInput]);

    useEffect(()=>{

        if(userId>=1 && userId<=24) {
            console.log('User ID set:', userId);
            //playCue(cuelist.find(c => c.id === refCurrentCue.current.nextcue)); // Play cue 5 when userId is set            
        }

    },[userId]);

    function onSpeechEnd(){

        sendOsc(OSC_ADDRESS.SPEECH, 'stop');

        if(currentCue?.type!='chat') return; // Only process if current cue is user input        
        if(chatStatus!=ChatStatus.User) return; // Only process if chat status is User
       
        console.log('~~~ on speech end, start pause timer',data.speech_idle_time);
        // refSpeechPaused.current=true;

        if(refPauseTimer.current) clearTimeout(refPauseTimer.current);
        refPauseTimer.current=setTimeout(()=>{
            console.log('~~~ pause timer ended, process speech');
            // if(refSpeechPaused.current) 
            processSpeech();
        }, data.speech_idle_time);
        
    }
    function processSpeech(){
        
         if(currentCue?.type!='chat') return; // Only process if current cue is user input        
       
        console.log('processSpeech:', finalTranscript);

        if(refChatCueEnd.current) {
            console.log('Chat cue has ended, do not processing speech');
            onCueEnd();
            return;
        }
        if(autoSend && transcript.trim().length > 0) {
            console.log('Auto sending transcript:', transcript);
            // onCueEnd(); 

            const message= refInput.current?.value?.trim();
            if(message && message.length>0) {
                console.log('Ending conversation with message:', message);
                sendMessage(message, false, false, null);
                setChatWelcome(false);
                
                setChatStatus(ChatStatus.Processing); // Set chat status to Processing
            }
            resetTranscript();
        }
    }
    function manualSendMessage() {
        if(currentCue?.type!='chat') return; // Only process if current cue is user input
        if(chatStatus!=ChatStatus.User) return; // Only process if chat status is User

        const message= refInput.current?.value?.trim();
        if(message && message.length>0) {
            console.log('Manual sending message:', message);
            sendMessage(message, false, false, null);
            setChatWelcome(false);
            setChatStatus(ChatStatus.Processing); // Set chat status to Processing
        
        }
        resetTranscript();

    }

    useEffect(()=>{

        console.log('Final transcript changed:', finalTranscript);
        if(finalTranscript.trim().length > 0) {
            onSpeechEnd(); 
        }

    },[finalTranscript]);

    function startRecognition() {

        SpeechRecognition.startListening({ continuous: true, language: 'zh-TW' }).then(() => {
            console.log("Speech recognition started.");
        }).catch(error => {
            console.error("Error starting speech recognition:", error);
        });
    }

    function blurText(text) {
        if(!text) return '';
        return text.replace(/./g, '*');
    }

    useEffect(()=>{
        if(audioInput && isMicrophoneAvailable) {
           
            startRecognition();

            const recognition= SpeechRecognition.getRecognition();

            recognition.onspeechstart=(e)=>{

                console.log('Speech start:', e);
              

            };
            // recognition.onspeechend=(e)=>{
            //     console.log('Speech end:', e);
            //     startRecognition();
            // };
            


        }else{
            console.log('Stopping speech recognition...');
            SpeechRecognition.stopListening();
        }

    },[audioInput]);

    
    useEffect(()=>{
        
     

        if((currentCue?.type=='chat' && chatStatus==ChatStatus.User) || currentCue?.type=='user_input') {

            // console.log('transcript state changed:', transcript);

            if(transcript!=finalTranscript){
                refInput.current.value = transcript;

                // clear pause timer
                // console.log('~~~~ clear pause timer');
                if(refPauseTimer.current) clearTimeout(refPauseTimer.current);
                refSpeechPaused.current=false;
            }
            
            sendOsc(OSC_ADDRESS.SPEECH, 'start');

            sendOscStatus(OSC_ADDRESS.CLIENT_INPUT, `${data.id}#${transcript}`);
            // Send current input via OSC
            
            
        }        

    },[transcript]);


    useEffect(()=>{

        if(refCurrentCue.current?.type!='chat') return;

        if(audioUrl) playAudio(audioUrl);

    },[audioUrl]);
    useEffect(()=>{
        
        resetTranscript();

        let text='';
        switch(chatStatus) {
            case ChatStatus.System:
                text = '等我一下\n換我說囉';
                break;
            case ChatStatus.User:
                text = '換你說了';
                break;
            case ChatStatus.Processing:
                text = '記憶讀取中';
                break;
            case ChatStatus.Message:
                text = '請留言';
                break;
            case ChatStatus.Clear:
            default:
                text = '';
                break;
        }
        sendOsc(OSC_ADDRESS.SPEECH, 'stop');
        sendOsc(OSC_ADDRESS.INPUT, text);

    },[chatStatus]);

    useEffect(()=>{
        switch(status) {            
            case Status.SUCCESS:
                console.log('Success!');                

                setStatus(Status.IDLE);
                refInput.current.value = '';
                resetTranscript();

                refContainer.current.scrollTop = refContainer.current.scrollHeight;

                break;
        }

    },[status]);

    useEffect(()=>{

        if(!nextCue) return;
        console.log('Next cue:', nextCue);

        const next=cuelist.find(c => c.name === nextCue);
        if(currentCue?.fadeout){
            // fade out audio
            fadeOutAudio(()=>{
                console.log('fade out then play next cue:', next);
                playCue(next);
                setNextCue(()=>null);
            });


        }else{
           
            playCue(next);
            setNextCue(null);
        }


    },[nextCue]);


    useEffect(()=>{
        fetch(CUELIST_FILE)
            .then(response => response.json())
            .then(data => {
                console.log('Cuelist data:', data);
                setCuelist(data.cuelist);
            })
            .catch(error => {
                console.error('Error fetching cuelist:', error);
            });


        refAudioPrompt.current = new Audio('assets/sfx/sfx-05.mp3'); // Load audio prompt if available

        onOscMessageReceived(onOsc); // Set up OSC message listener

        invoke('get_ip').then((ip)=>{
            console.log('Local IP address:', ip);        
            setLocalIP(ip);
        });

    },[]);


    return (
        <main className="items-start">
            <section className="flex-1 flex flex-col gap-2 self-stretch overflow-hidden">
                <div className="bg-purple-300 text-3xl flex flex-row justify-between px-4 items-center gap-1">
                    <span className='font-bold'>PC {data?.id}</span>
                    <span className="">{localIP || '...'}</span>
                </div>
                <DebugControl onReset={resetData}/>                
                <div className="w-full p-2 grid grid-cols-3 gap-2 items-stretch justify-center *:max-h-[5rem]">
                    <div className="bg-gray-100 text-4xl font-bold mb-4 flex justify-center items-center">
                        {refCurrentCue.current?.name}
                    </div>
                    <Countdown ref={refTimer} clientId={data?.id}/>
                    <button className="!bg-red-300" onClick={onStop}>Stop</button>
                    
                    {/* <button onClick={saveImage}>Save image</button> */}
                    <NumPad onSend={onNumpad} 
                        disabled={currentCue?.callback !== 'numpad' || !inputReady} 
                        type={currentCue?.numpad_type}
                        clientId={data?.id}
                    />
                    {/* <Light ref={refLight} /> */}
                    {/* <VoiceAnalysis/> */}
                    
                    {/* <div className="flex flex-col">
                        <label className="text-center">Voice</label>
                        <button className={`${voice==Voice.ONYX && 'bg-gray-300'}`} onClick={() => setVoice(Voice.ONYX)}>Onyx</button>
                        <button className={`${voice==Voice.SHIMMER && 'bg-gray-300'}`} onClick={() => setVoice(Voice.SHIMMER)}>Shimmer</button>
                    </div> */}
                                 
                    <div className="grid grid-cols-[1fr_2fr] relative text-xs">
                        <label className="col-span-1">user</label>
                        <span></span>
                        <span>UserId</span><span>{userId}</span>
                        <span>FileId</span><span>{getFileId()}</span>
                        <span>Choice</span><span>{choice || ''}</span>
                    </div>

                    
                </div>
                <div className="flex-1 overflow-y-auto">
                    <table className="border-collapse **:border-y w-full **:p-2 text-sm">
                        <thead>
                            <tr className="text-left">
                                {/* <th>ID</th> */}
                                <th></th>
                                <th>Name</th>
                                <th>Description</th>
                                <th>Type</th>
                                <th>Auto</th>
                                <th>Audio</th>
                                <th>Duration</th>
                                <th>Action</th>                                
                            </tr>
                        </thead>
                        <tbody>
                            {cuelist?.map(({id, name, description, type, auto, audioFile,...props}, index) => (
                                <tr key={id}>
                                    {/* <td>{id}</td> */}
                                    <td>
                                        <button className="rounded-full !bg-green-200"
                                            onClick={()=>{
                                                // playCue({id, name, description, type, auto, audioFile, ...props});
                                                setNextCue(()=>name);
                                            }}>go</button>
                                    </td>
                                    <td>{name}</td>
                                    <td>{description}</td>
                                    <td>{EmojiType[type]}</td>
                                    <td>{auto ? '⤵️' : ''}</td>
                                    <td>{audioFile || ""}</td>
                                    <td>{props.duration || ''}</td>
                                    <td>{props.callback && `<${props.callback}>`}{props.status && `(${props.status})`}</td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            </section>
            <section className="flex-1 self-stretch overflow-y-auto flex flex-col justify-end gap-2 ">
                 <div ref={refContainer} className="flex-1 flex flex-col overflow-y-auto gap-2 blur-sm" >
                    {history?.map((msg, index) => (
                        <div key={index} className={`w-5/6 ${msg.role=='user'? 'self-end':''}`}>
                            <div className={`${msg.role=='user'? 'bg-green-300':'bg-pink-300'} px-2`}>{blurText(msg.content)}</div>
                            {msg.prompt && <div className="text-xs bg-gray-200">{blurText(msg.prompt)}</div>}
                        </div>
                    ))}
                    {summary && <div className="w-full self-center bg-blue-200 px-2">{summary}</div>}
                </div>
                <textarea ref={refInput} name="message" rows={2} 
                    className={`w-full border-1 resize-none p-2 disabled:bg-gray-500 blur-sm`}
                    disabled={chatStatus!=ChatStatus.User && chatStatus!=ChatStatus.Message}></textarea>       
                <div className="flex flex-row justify-end gap-2 flex-wrap">
                    <span className="flex flex-row gap-1">
                        <label>audio_output</label>
                        <input type='checkbox' checked={audioOutput} onChange={(e) => setAudioOutput(e.target.checked)} />
                    </span>
                    <span className="flex flex-row gap-1">
                        <label>audio_input</label>
                        <input type='checkbox' checked={audioInput} onChange={(e) => setAudioInput(e.target.checked)} />
                    </span>
                    <span className="flex flex-row gap-1">
                        <label>auto_send</label>
                        <input type='checkbox' checked={autoSend} onChange={(e) => setAutoSend(e.target.checked)} />
                    </span>
                    <button onClick={resetTranscript}>reset transcript</button>
                    <button onClick={manualSendMessage} disabled={chatStatus!=ChatStatus.User && chatStatus!=ChatStatus.Message}>Send</button>

                    <div className="rounded-2xl bg-gray-300 self-end px-4 tracking-widest">api_status= {status}</div>                                                                
                    <div className="rounded-2xl bg-gray-300 self-end px-4 tracking-widest">chat_status= {chatStatus}</div>                                                                
                </div>
            </section>
        </main>
    );
}