let currentPreviewStream = null;
let copuloo_room;
var copuloo_token;
var copuloo_videoroom = CopulooVideoCallingVars.copulooRoom;
var copuloo_Url = CopulooVideoCallingVars.copulooUrl;
var copuloo_User = CopulooVideoCallingVars.copulooUser;
var copuloo_Nonce = CopulooVideoCallingVars.copulooNonce;

const input1 = document.getElementById('videoRoomName');
const button1 = document.getElementById('getTwilioVideoChatToken');
const button2 = document.getElementById('disconnectTwilioVideoChat');
input1.addEventListener('input', (e) => {
    copuloo_videoroom = e.target.value;
});
button1.addEventListener('click', copuloo_createTwilioVideoRoom);
button2.addEventListener('click', copuloo_disconnectVideoCall);

async function populateCameraAndMic() {
    const micSelect = document.getElementById('copuloomicrophoneSelect');
    const cameraSelect = document.getElementById('copuloocameraSelect');
    const speakerSelect = document.getElementById('copuloospeakerSelect');
    const preview = document.getElementById('mainVideo');
    const placeholder = document.getElementById('cameraPlaceholder');
    let permissionStream = null;

    try {
        // Request permissions so device labels are available
        try { permissionStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: false }); } catch (error) {}
        try { permissionStream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true }); } catch (error) {}
        const devices = await navigator.mediaDevices.enumerateDevices();
        permissionStream.getTracks().forEach(track => track.stop());
        micSelect.innerHTML = '';
        cameraSelect.innerHTML = '';
        speakerSelect.innerHTML = '';
        // Get default
        devices.forEach(device => {
            const option = document.createElement('option');
            option.value = device.deviceId;
            option.textContent = device.label || 'Unknown device';
            if (device.label.toLowerCase().includes('default')) {
                if (device.kind === 'audioinput') micSelect.appendChild(option);
                if (device.kind === 'videoinput') cameraSelect.appendChild(option);
                if (device.kind === 'audiooutput') speakerSelect.appendChild(option);
            }
        });
        // append everything else
        devices.forEach(device => {
            const option = document.createElement('option');
            option.value = device.deviceId;
            option.textContent = device.label || 'Unknown device';
            if (!device.label.toLowerCase().includes('default')) {
                if (device.kind === 'audioinput') micSelect.appendChild(option);
                if (device.kind === 'videoinput') cameraSelect.appendChild(option);
                if (device.kind === 'audiooutput') speakerSelect.appendChild(option);
            }
        });
        // camera and mic off option
        const offOption = document.createElement('option');
        offOption.value = '';
        offOption.textContent = 'Camera Off';
        cameraSelect.appendChild(offOption);
        const offOption2 = document.createElement('option');
        offOption2.value = '';
        offOption2.textContent = 'Microphone Off';
        micSelect.appendChild(offOption2);

        if (!micSelect.options.length) {
            micSelect.innerHTML = '<option>No microphone detected</option>';
        }

        if (!speakerSelect.options.length) {
            speakerSelect.innerHTML = '<option>No speaker detected</option>';
        }

        if (!cameraSelect.options.length) {
            cameraSelect.innerHTML = '<option>No camera detected</option>';
        }

        // Camera preview on change
        cameraSelect.onchange = async () => {
            // Stop previous preview
            if (currentPreviewStream) {
                currentPreviewStream.getTracks().forEach(t => t.stop());
                currentPreviewStream = null;
            }

            // NO CAMERA → use blank video
            if (!cameraSelect.value) {
                currentPreviewStream = createBlankVideoStream();
                preview.srcObject = currentPreviewStream;
                preview.style.display = 'block';
                return;
            }

            // REAL CAMERA
            currentPreviewStream = await navigator.mediaDevices.getUserMedia({
                video: { deviceId: { exact: cameraSelect.value } }
            });

            preview.srcObject = currentPreviewStream;
            preview.style.display = 'block';
        };
        speakerSelect.onchange = () => {
            applySpeakerToAllAudioElements(speakerSelect.value);
        };

        // Start preview with first available camera
        if (cameraSelect.value) {
            cameraSelect.onchange();
        }

    } catch (error) {
        currentPreviewStream = createBlankVideoStream();
        preview.srcObject = currentPreviewStream;
        preview.style.display = 'block';
        micSelect.innerHTML = '<option>No microphone detected</option>';
        speakerSelect.innerHTML = '<option>No speaker detected</option>';
        cameraSelect.innerHTML = '<option>No camera detected</option>';
        return;
    }
}
function applySpeakerToAllAudioElements(speakerId) {
    if (!speakerId || !HTMLMediaElement.prototype.setSinkId) return;

    document.querySelectorAll('audio').forEach(audio => {
        audio.setSinkId(speakerId).catch(err => {
            console.warn('Speaker change failed:', err);
        });
    });
}
async function createSelectedTracks() {
    const micId = document.getElementById('copuloomicrophoneSelect')?.value;
    const camId = document.getElementById('copuloocameraSelect')?.value;
    const speakerId = document.getElementById('copuloospeakerSelect')?.value;
    let videoTrack;
    let audioTrack;
    if (speakerId && typeof HTMLMediaElement.prototype.setSinkId === 'function') {
        applySpeakerToAllAudioElements(speakerId);
    }

    if (micId || micId !== '') { 
        audioTrack = await Twilio.Video.createLocalAudioTrack({
        deviceId: { exact: micId }
    });
    } else { audioTrack = createSilentAudioTrack(); }
    if (camId && camId !== '') {
        videoTrack = await Twilio.Video.createLocalVideoTrack({
        deviceId: { exact: camId }
    }); 
    } else { videoTrack = createBlankVideoTrack(); }
    // SAFETY CHECK
    if (!videoTrack.mediaStreamTrack.readyState === 'live') {
        alert('Camera track is not live');
        button1.disabled = false; button1.innerHTML = 'Start / Join';
        document.getElementById('copuloomicrophoneSelect').disabled = false; document.getElementById('copuloospeakerSelect').disabled = false; document.getElementById('copuloocameraSelect').disabled = false;
    }

    return [audioTrack,videoTrack];
}
async function copuloo_createTwilioVideoRoom()
{
    if (copuloo_videoroom == '') { alert('Could not connect to video call. Room name cannot be empty.'); button1.disabled = false; button1.innerHTML = 'Start / Join'; return; }
    input1.disabled = true;
    document.getElementById('copuloomicrophoneSelect').disabled = true; document.getElementById('copuloospeakerSelect').disabled = true; document.getElementById('copuloocameraSelect').disabled = true;
    const response = await fetch(copuloo_Url, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        },
        body: new URLSearchParams({
            action: 'copuloo_get_video_call_token',
            user_nonce: copuloo_Nonce,
            copuloo_user: copuloo_User,
            videoroom: copuloo_videoroom
        })
    });
    if (response.ok)
    {
        const data = await response.json();
        const tracks = await createSelectedTracks();
        copuloo_room = await Twilio.Video.connect(data.data.token, {
            name: copuloo_videoroom,
            tracks,
            dominantSpeaker: true
        });
        if (copuloo_room && copuloo_room.state === 'connected')
        {
            copuloo_room.participants.forEach(addRemoteParticipant);
            addLocalParticipant(copuloo_room);
            copuloo_room.on('participantConnected', addRemoteParticipant);
            copuloo_room.on('participantDisconnected', participant => {
                document.querySelectorAll('.participant')
                    .forEach(el => {
                        if (el.querySelector('.participant-name')?.textContent === participant.identity) {
                            el.remove();
                        }
                    });
            });
            copuloo_room.on('trackSubscribed', track => {
                if (track.kind === 'audio') {
                    const el = track.attach();
                    document.body.appendChild(el);

                    const speakerId = document.getElementById('copuloospeakerSelect')?.value;
                    if (speakerId && el.setSinkId) {
                        el.setSinkId(speakerId);
                    }
                }
            });
            copuloo_room.on('participantConnected', participant => {
                setMainVideo(participant);
            });
            button1.disabled = false; button1.innerHTML = 'Start / Join'; button1.style.display = 'none'; button2.style.display = 'block';

        } else { alert('Failed to connect and error starting/joining video call. Twilio API keys are likely incorrect.'); input1.disabled = false; document.getElementById('copuloomicrophoneSelect').disabled = false; document.getElementById('copuloospeakerSelect').disabled = false; document.getElementById('copuloocameraSelect').disabled = false; }
    }
    else { alert('Error starting video call. Twilio API keys are likely incorrect.'); input1.disabled = false; document.getElementById('copuloomicrophoneSelect').disabled = false; document.getElementById('copuloospeakerSelect').disabled = false; document.getElementById('copuloocameraSelect').disabled = false; }
}
async function copuloo_disconnectVideoCall() 
{
    if (copuloo_room && copuloo_room.state === 'connected')
    {
        copuloo_room.disconnect();
        //button2.innerHTML = 'Disconnect'; button2.style.display = 'none'; button2.disabled = false; button1.innerHTML = 'Start / Join'; button1.style.display = 'block'; input1.disabled = false;
        window.location.reload();
        
    } else { alert('Failed to disconnect. Not connected to any video call.'); }
}
function createSilentAudioTrack() {
    const audioContext = new AudioContext();

    const oscillator = audioContext.createOscillator();
    const gainNode = audioContext.createGain();

    gainNode.gain.value = 0; // silence

    oscillator.connect(gainNode);

    const destination = audioContext.createMediaStreamDestination();
    gainNode.connect(destination);

    oscillator.start();

    const track = destination.stream.getAudioTracks()[0];

    return new Twilio.Video.LocalAudioTrack(track, {
        name: 'silent-audio'
    });
}
function createBlankVideoTrack({ width = 640, height = 360 } = {}) {
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;

    const ctx = canvas.getContext('2d');
    ctx.fillStyle = '#000'; // black background
    ctx.fillRect(0, 0, width, height);

    // Capture canvas as a MediaStream
    const stream = canvas.captureStream(5); // low FPS is fine
    const track = stream.getVideoTracks()[0];

    return new Twilio.Video.LocalVideoTrack(track, {
        name: 'blank-video'
    });
}
function createBlankVideoStream(width = 640, height = 360, fps = 15) {
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;

    const ctx = canvas.getContext('2d');

    // Draw solid black frame continuously
    function draw() {
        ctx.fillStyle = '#000';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        requestAnimationFrame(draw);
    }
    draw();

    return canvas.captureStream(fps);
}
function createParticipantElement(participant, track) {
    const wrapper = document.createElement('div');
    wrapper.className = 'participant col-xl-3 col-lg-3 col-md-4 col-sm-3';
    wrapper.style.pointerEvents = 'auto';

    const videoEl = track.attach();
    videoEl.style.width = '100%';
    videoEl.style.height = '100%';
    videoEl.style.objectFit = 'cover';
    videoEl.className = 'participant-video';
    videoEl.dataset.sid = participant.sid;
    wrapper.appendChild(videoEl);

    const name = document.createElement('div');
    name.className = 'participant-name';
    name.textContent = participant.identity;
    wrapper.appendChild(name);

    wrapper.addEventListener('click', () => {
        setMainVideo(track, participant);
    });

    return wrapper;
}
function setMainVideo(track, participant) {
    const mainVideo = document.getElementById('mainVideo');
    if (!mainVideo) return;

    // Save scroll position
    const scrollX = window.scrollX;
    const scrollY = window.scrollY;

    // Prevent focus-based scrolling
    mainVideo.blur?.({ preventScroll: true });

    // Reset stream
    if (mainVideo.srcObject) {
        mainVideo.pause();
        mainVideo.srcObject = null;
    }

    // Set new stream
    mainVideo.srcObject = new MediaStream([track.mediaStreamTrack]);
    mainVideo.style.width = '100%';
    mainVideo.style.height = '100%';
    mainVideo.style.objectFit = 'contain';

    mainVideo.autoplay = true;
    mainVideo.muted = true;
    mainVideo.playsInline = true;

    // Restore scroll (Safari + Chrome safety)
    requestAnimationFrame(() => {
        window.scrollTo(scrollX, scrollY);
    });
}
function addLocalParticipant(room) {
    room.localParticipant.videoTracks.forEach(publication => {
        if (publication.track) {
            addVideoTrack(room.localParticipant, publication.track);
        }
    });
}
function addRemoteParticipant(participant) {
    participant.tracks.forEach(publication => {
        if (publication.track?.kind === 'video') {
            const el = createParticipantElement(participant, publication.track);
            document.getElementById('participantBar').appendChild(el);
        }
    });
    participant.on('trackSubscribed', track => {
        if (track.kind === 'video') {
            addVideoTrack(participant, track);
        }
    });
}
function addVideoTrack(participant, track) {
    const el = createParticipantElement(participant, track);
    document.getElementById('participantBar').appendChild(el);

    // If no main video yet, set this one
    const main = document.getElementById('mainVideo');
    if (!main.dataset.trackSid) {
        setMainVideo(track, participant);
        main.dataset.trackSid = track.sid;
    }
}
function toggleFullscreen(video) {
    if (!document.fullscreenElement) {
        if (video.requestFullscreen) {
            video.requestFullscreen();
        } else if (video.webkitRequestFullscreen) {
            video.webkitRequestFullscreen(); // Safari
        }
    } else {
        document.exitFullscreen();
    }
}
async function togglePiP(video) {
    if (!document.pictureInPictureElement) {
        try {
            await video.requestPictureInPicture();
        } catch (err) {
            alert('PiP not supported', err);
        }
    } else {
        await document.exitPictureInPicture();
    }
}
document.addEventListener('DOMContentLoaded', populateCameraAndMic);
document.getElementById('videoFullScreen').onclick = () => toggleFullscreen(document.getElementById('mainVideo'));
document.getElementById('videoPictureInPicture').onclick = () => togglePiP(document.getElementById('mainVideo'));