import {useState, useRef, useEffect} from 'react';
import useLoginToken from "../Hooks/useLoginToken.tsx";
import { z } from 'zod/v4';

function SessionActive({stopSession} : {stopSession: () => void})
{
    return <button onClick={stopSession}>Stop session</button>
}

function SessionStopped({startSession} : {startSession: () => void})
{
    return <button onClick={startSession}>Start session</button>
}

function SessionControl( { isSessionActive, startSession, stopSession }: { isSessionActive: boolean, startSession : () => void, stopSession : () => void })
{
    return (isSessionActive
        ? <SessionActive stopSession={stopSession}/>
        : <SessionStopped startSession={startSession}/>);
}

const EphemeralTokenResponse = z.object({
    ephemeralToken: z.string(),
    expiresAt: z.number(),
});

export function ChatControl() 
{
    const { token } = useLoginToken();

    const [isSessionActive, setSessionActive] = useState<boolean>(false);
    const [dataChannel, setDataChannel] = useState<RTCDataChannel | null>(null);
    const audioElement = useRef<HTMLAudioElement>(null);
    const peerConnection = useRef<RTCPeerConnection>(null);

    async function StartSession() 
    {
        // Get a session token for OpenAI Realtime API
        const response = await fetch('ephemeral_token', {
            method: "GET",
            headers: {
                Authorization: `Bearer ${token}asdasd`
            },
        });
        if (!response.ok) 
        {
            throw new Error(response.statusText);
        }

        const responseJson:unknown = await response.json();
        const parsedToken = EphemeralTokenResponse.parse(responseJson);
        const ephemeralToken = parsedToken.ephemeralToken;

        // Create a peer connection
        const pc = new RTCPeerConnection();

        // Set up to play remote audio from the model
        audioElement.current = document.createElement("audio");
        audioElement.current.autoplay = true;
        pc.ontrack = (e) => 
        {
            if (audioElement.current !== null)
            {
                audioElement.current.srcObject = e.streams[0];
            }
        }

        // Add local audio track for microphone input in the browser
        const microphoneStream = await navigator.mediaDevices.getUserMedia({audio: true});
        pc.addTrack(microphoneStream.getTracks()[0]);

        // Set up data channel for sending and receving events
        const dc = pc.createDataChannel("oai-events");
        setDataChannel(dc)

        // Start the session using the Session Description Protocol (SDP)
        const offer = await pc.createOffer();
        await pc.setLocalDescription(offer);

        // Start Realtime Session
        const baseUrl = "https://api.openai.com/v1/realtime";
        const model = "gpt-4o-realtime-preview";
        const sdpResponse = await fetch(`${baseUrl}?model=${model}`, {
            method: "POST",
            body: offer.sdp,
            headers: {
                Authorization: `Bearer ${ephemeralToken}`,
                "Content-Type": "application/sdp",
            },
        });

        const answer:RTCSessionDescriptionInit = {
            type: "answer",
            sdp: await sdpResponse.text(),
        };
        await pc.setRemoteDescription(answer);

        peerConnection.current = pc;
    }

    function stopSession() 
    {
        if (dataChannel) 
        {
            dataChannel.close();
            setDataChannel(null);
        }

        if (peerConnection.current !== null)
        {
            peerConnection.current.close();
            peerConnection.current = null;
        }

        setSessionActive(false);
    }

    useEffect(() => 
    {
        if (dataChannel) 
        {
            dataChannel.addEventListener("open", () => 
            {
                setSessionActive(true);
            });
        }
    }, [dataChannel])

    return <SessionControl isSessionActive={isSessionActive} startSession={() => void StartSession()} stopSession={stopSession}/>;
}