(function(window, document) {
    'use strict';

    if (window.__vmoPhoneBridgeLoaded) {
        return;
    }
    window.__vmoPhoneBridgeLoaded = true;

    if (document.querySelector('.vmo-hud')) {
        console.log('[VMO Phone Bridge] Strategic dashboard detected; standalone bridge disabled on this screen.');
        return;
    }

    const cfg = window.vmoPhoneBridge || {};
    const actionAliases = Object.assign({
        vmo_get_live_calls: 'vmo_sd_phone_live',
        vmo_call_action: 'vmo_sd_phone_control',
        vmo_twilio_browser_token: 'vmo_sd_phone_token',
        vmo_end_call: 'vmo_sd_phone_end',
        vmo_get_call_transcript: 'vmo_sd_phone_transcript'
    }, cfg.actionAliases || {});
    if (!cfg.ajaxurl) {
        console.warn('[VMO Phone Bridge] Missing configuration; bridge not started.');
        return;
    }

    const state = {
        panel: null,
        callerEl: null,
        statusEl: null,
        badgeEl: null,
        listenBtn: null,
        takeoverBtn: null,
        openDialerBtn: null,
        dismissBtn: null,
        disconnectBtn: null,
        isVisible: false,
        isRinging: false,
        ringTimer: null,
        titleTimer: null,
        originalTitle: document.title,
        audioContext: null,
        currentCall: null,
        currentMode: 'idle',
        currentConference: '',
        pendingIncomingConn: null,
        isMuted: false,
        isOnHold: false,
        twilioDevice: null,
        twilioReady: false,
        twilioInitPromise: null,
        browserLiveAudioPrimed: false,
        browserLiveAudioPrimePromise: null,
        browserConnection: null,
        bridgeListen: null,
        lastRingSid: '',
        dismissedIncoming: {},
        pollTimer: null,
        activePoll: false,
        endingCall: false
    };

    function log() {
        const args = Array.prototype.slice.call(arguments);
        args.unshift('[VMO Phone Bridge]');
        console.log.apply(console, args);
    }

    function notify(message, type) {
        if (!message) {
            return;
        }
        if (typeof window.showToast === 'function') {
            window.showToast(message, type || 'info');
            return;
        }
        if (typeof window.notify === 'function') {
            window.notify(message, type || 'info');
            return;
        }
        log(message);
    }

    function injectStyles() {
        if (document.getElementById('vmo-phone-bridge-styles')) {
            return;
        }
        const style = document.createElement('style');
        style.id = 'vmo-phone-bridge-styles';
        style.textContent = [
            '#vmo-phone-bridge{position:fixed;right:24px;bottom:24px;z-index:999999;display:none;min-width:320px;max-width:380px;padding:16px 16px 14px;border-radius:18px;background:linear-gradient(180deg,rgba(6,13,24,.96),rgba(10,18,34,.96));border:1px solid rgba(15,225,255,.25);box-shadow:0 18px 50px rgba(0,0,0,.38);backdrop-filter:blur(18px);color:#eef9ff;font-family:Arial,Helvetica,sans-serif;}',
            '#vmo-phone-bridge.vmo-phone-bridge-live{border-color:rgba(16,185,129,.35);}',
            '#vmo-phone-bridge .vmo-phone-bridge-top{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:8px;}',
            '#vmo-phone-bridge .vmo-phone-bridge-badge{display:inline-flex;align-items:center;gap:6px;padding:4px 10px;border-radius:999px;background:rgba(15,225,255,.12);color:#8ff6ff;font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;}',
            '#vmo-phone-bridge .vmo-phone-bridge-dot{width:8px;height:8px;border-radius:50%;background:#0fe1ff;box-shadow:0 0 12px rgba(15,225,255,.9);}',
            '#vmo-phone-bridge .vmo-phone-bridge-caller{font-size:18px;font-weight:700;line-height:1.3;margin:4px 0 6px;word-break:break-word;}',
            '#vmo-phone-bridge .vmo-phone-bridge-status{font-size:13px;line-height:1.5;color:#c7d8e8;min-height:38px;}',
            '#vmo-phone-bridge .vmo-phone-bridge-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px;}',
            '#vmo-phone-bridge .vmo-phone-bridge-btn{appearance:none;border:0;border-radius:12px;padding:10px 14px;font-size:13px;font-weight:700;cursor:pointer;transition:transform .15s ease, opacity .15s ease;background:#1f3147;color:#eef9ff;}',
            '#vmo-phone-bridge .vmo-phone-bridge-btn:hover{transform:translateY(-1px);}',
            '#vmo-phone-bridge .vmo-phone-bridge-btn[disabled]{opacity:.55;cursor:wait;transform:none;}',
            '#vmo-phone-bridge .vmo-phone-bridge-btn-primary{background:linear-gradient(135deg,#0fe1ff,#1490ff);color:#04121a;}',
            '#vmo-phone-bridge .vmo-phone-bridge-btn-secondary{background:rgba(56,189,248,.18);color:#a8f0ff;border:1px solid rgba(56,189,248,.28);}',
            '#vmo-phone-bridge .vmo-phone-bridge-btn-neutral{background:rgba(148,163,184,.16);color:#eef9ff;border:1px solid rgba(148,163,184,.22);}',
            '#vmo-phone-bridge .vmo-phone-bridge-btn-danger{background:rgba(239,68,68,.14);color:#ffcaca;border:1px solid rgba(239,68,68,.24);}',
            '@media (max-width: 640px){#vmo-phone-bridge{left:12px;right:12px;bottom:12px;min-width:auto;max-width:none;}}'
        ].join('');
        document.head.appendChild(style);
    }

    function createPanel() {
        if (state.panel) {
            return;
        }
        injectStyles();

        const panel = document.createElement('div');
        panel.id = 'vmo-phone-bridge';
        panel.innerHTML = '' +
            '<div class="vmo-phone-bridge-top">' +
                '<div class="vmo-phone-bridge-badge" id="vmo-phone-bridge-badge">' +
                    '<span class="vmo-phone-bridge-dot"></span>' +
                    '<span>Incoming Call</span>' +
                '</div>' +
            '</div>' +
            '<div class="vmo-phone-bridge-caller" id="vmo-phone-bridge-caller">Unknown Caller</div>' +
            '<div class="vmo-phone-bridge-status" id="vmo-phone-bridge-status">Take over or listen live.</div>' +
            '<div class="vmo-phone-bridge-actions">' +
                '<button type="button" class="vmo-phone-bridge-btn vmo-phone-bridge-btn-secondary" id="vmo-phone-bridge-listen">Listen</button>' +
                '<button type="button" class="vmo-phone-bridge-btn vmo-phone-bridge-btn-primary" id="vmo-phone-bridge-takeover">Take Over</button>' +
                '<button type="button" class="vmo-phone-bridge-btn vmo-phone-bridge-btn-neutral" id="vmo-phone-bridge-hold" style="display:none;">Hold</button>' +
                '<button type="button" class="vmo-phone-bridge-btn vmo-phone-bridge-btn-neutral" id="vmo-phone-bridge-mute" style="display:none;">Mute</button>' +
                '<button type="button" class="vmo-phone-bridge-btn vmo-phone-bridge-btn-neutral" id="vmo-phone-bridge-open">Dialer</button>' +
                '<button type="button" class="vmo-phone-bridge-btn vmo-phone-bridge-btn-neutral" id="vmo-phone-bridge-dismiss">Dismiss</button>' +
                '<button type="button" class="vmo-phone-bridge-btn vmo-phone-bridge-btn-danger" id="vmo-phone-bridge-disconnect" style="display:none;">End Call</button>' +
            '</div>';

        document.body.appendChild(panel);

        state.panel = panel;
        state.callerEl = panel.querySelector('#vmo-phone-bridge-caller');
        state.statusEl = panel.querySelector('#vmo-phone-bridge-status');
        state.badgeEl = panel.querySelector('#vmo-phone-bridge-badge');
        state.listenBtn = panel.querySelector('#vmo-phone-bridge-listen');
        state.takeoverBtn = panel.querySelector('#vmo-phone-bridge-takeover');
        state.holdBtn = panel.querySelector('#vmo-phone-bridge-hold');
        state.muteBtn = panel.querySelector('#vmo-phone-bridge-mute');
        state.openDialerBtn = panel.querySelector('#vmo-phone-bridge-open');
        state.dismissBtn = panel.querySelector('#vmo-phone-bridge-dismiss');
        state.disconnectBtn = panel.querySelector('#vmo-phone-bridge-disconnect');

        state.listenBtn.addEventListener('click', function() {
            handleListen();
        });
        state.takeoverBtn.addEventListener('click', function() {
            handleTakeOver();
        });
        state.holdBtn.addEventListener('click', function() {
            handleHold();
        });
        state.muteBtn.addEventListener('click', function() {
            handleMute();
        });
        state.openDialerBtn.addEventListener('click', function() {
            openLiveDialer();
        });
        state.dismissBtn.addEventListener('click', function() {
            dismissIncomingCall();
        });
        state.disconnectBtn.addEventListener('click', function() {
            endActiveCallEverywhere('browser_button');
        });
    }

    function setButtonsDisabled(disabled) {
        [state.listenBtn, state.takeoverBtn, state.holdBtn, state.muteBtn, state.openDialerBtn, state.dismissBtn, state.disconnectBtn].forEach(function(btn) {
            if (btn) {
                btn.disabled = !!disabled;
            }
        });
    }

    function renderPanel() {
        createPanel();

        if (!state.currentCall) {
            state.panel.style.display = 'none';
            state.panel.classList.remove('vmo-phone-bridge-live');
            return;
        }

        const caller = state.currentCall.from_number || state.currentCall.caller || 'Unknown Caller';
        const incoming = state.currentMode === 'incoming' || state.currentMode === 'idle';
        const listening = state.currentMode === 'listen';
        const connected = state.currentMode === 'join';

        state.panel.style.display = 'block';
        state.panel.classList.toggle('vmo-phone-bridge-live', listening || connected);
        state.callerEl.textContent = caller;
        state.statusEl.textContent = state.currentCall.statusText || (incoming
            ? 'Take over or listen live while AI handles the caller.'
            : (listening ? 'Listening live. You can take over at any time.' : 'Browser audio is connected to the call.'));
        state.badgeEl.lastElementChild.textContent = incoming ? 'Incoming Call' : (listening ? 'Listening Live' : 'Call Connected');
        state.listenBtn.style.display = connected ? 'none' : '';
        state.listenBtn.textContent = listening ? 'Listening...' : 'Listen';
        state.takeoverBtn.textContent = connected ? 'Connected' : 'Take Over';
        state.holdBtn.style.display = (connected || listening) ? '' : 'none';
        state.holdBtn.textContent = state.isOnHold ? 'Resume' : 'Hold';
        state.muteBtn.style.display = (connected && state.browserConnection) ? '' : 'none';
        state.muteBtn.textContent = state.isMuted ? 'Unmute' : 'Mute';
        state.openDialerBtn.style.display = '';
        state.dismissBtn.style.display = incoming ? '' : 'none';
        state.disconnectBtn.style.display = (state.browserConnection || state.bridgeListen) ? '' : 'none';
        state.listenBtn.disabled = listening;
        state.takeoverBtn.disabled = connected;
    }

    function currentCallSid(call) {
        return String((call && call.call_sid) || '');
    }

    function currentConnectionSid(connection) {
        return (connection && connection.parameters && connection.parameters.CallSid)
            ? String(connection.parameters.CallSid || '')
            : '';
    }

    function currentTeardownIds() {
        const callSid = currentCallSid(state.currentCall);
        const childSid = getPendingIncomingChildSid()
            || (state.currentCall && state.currentCall.browser_call_sid ? String(state.currentCall.browser_call_sid || '') : '')
            || currentConnectionSid(state.browserConnection);

        return {
            callSid: callSid,
            childSid: childSid,
            conferenceSid: state.currentConference || (state.currentCall && (state.currentCall.conference_sid || state.currentCall.conference_name)) || ''
        };
    }

    function isDismissedIncoming(call) {
        const sid = currentCallSid(call);
        return !!(sid && state.dismissedIncoming[sid]);
    }

    function clearDismissedIncoming(callSid) {
        const sid = String(callSid || '');
        if (sid) {
            delete state.dismissedIncoming[sid];
        }
    }

    function openLiveDialer() {
        if (cfg.dialerUrl) {
            window.location.href = cfg.dialerUrl;
            return;
        }
        notify('Live dialer link is not available on this page.', 'warning');
    }

    function dismissIncomingCall() {
        const sid = currentCallSid(state.currentCall);
        if (sid) {
            state.dismissedIncoming[sid] = Date.now();
        }
        stopRinging();
        if (!state.browserConnection) {
            resetCurrentCall();
            return;
        }
        renderPanel();
    }

    function flashTitleStart(caller) {
        if (state.titleTimer) {
            return;
        }
        const alt = 'Incoming call: ' + (caller || 'Unknown');
        let on = false;
        state.titleTimer = window.setInterval(function() {
            document.title = on ? state.originalTitle : alt;
            on = !on;
        }, 900);
    }

    function flashTitleStop() {
        if (state.titleTimer) {
            window.clearInterval(state.titleTimer);
            state.titleTimer = null;
        }
        document.title = state.originalTitle;
    }

    function ensureAudioContext() {
        const Ctx = window.AudioContext || window.webkitAudioContext;
        if (!Ctx) {
            return null;
        }
        if (!state.audioContext) {
            try {
                state.audioContext = new Ctx();
            } catch (e) {
                console.warn('[VMO Phone Bridge] AudioContext creation failed:', e);
                return null;
            }
        }
        return state.audioContext;
    }

    function isRingEnabled() {
        if (typeof cfg.ringEnabled !== 'undefined') {
            return !!cfg.ringEnabled;
        }
        return true;
    }

    function getRingVolume() {
        if (typeof cfg.ringVolume === 'number' && cfg.ringVolume >= 0 && cfg.ringVolume <= 1) {
            return cfg.ringVolume;
        }
        return 0.6;
    }

    function playRingBurst() {
        return; // Disabled synthetic ringer to prevent dual-ringing (
        if (!isRingEnabled()) {
            return;
        }
        const ctx = ensureAudioContext();
        if (!ctx) {
            return;
        }
        if (typeof ctx.resume === 'function' && ctx.state === 'suspended') {
            ctx.resume().catch(function() {});
        }
        var volume = getRingVolume();
        var peakGain = Math.max(0.001, volume * 0.13);
        [0, 0.22].forEach(function(offset) {
            const osc = ctx.createOscillator();
            const gain = ctx.createGain();
            osc.type = 'sine';
            osc.frequency.value = 880;
            gain.gain.value = 0.0001;
            osc.connect(gain);
            gain.connect(ctx.destination);
            const startAt = ctx.currentTime + offset;
            gain.gain.setValueAtTime(0.0001, startAt);
            gain.gain.exponentialRampToValueAtTime(peakGain, startAt + 0.02);
            gain.gain.exponentialRampToValueAtTime(0.0001, startAt + 0.16);
            osc.start(startAt);
            osc.stop(startAt + 0.18);
        });
    }


    function startRinging(caller) {
        if (state.isRinging) {
            return;
        }
        if (!isRingEnabled()) {
            flashTitleStart(caller);
            state.isRinging = true;
            return;
        }
        state.isRinging = true;
        flashTitleStart(caller);
        playRingBurst();
        state.ringTimer = window.setInterval(function() {
            playRingBurst();
        }, 2800);
    }

    function stopRinging() {
        state.isRinging = false;
        if (typeof window.stopSystemRinging === 'function') window.stopSystemRinging();
        if (state.currentCall && state.currentCall.call_sid && window.__handledSids) {
            window.__handledSids.add(state.currentCall.call_sid);
        }
        if (state.ringTimer) {
            window.clearInterval(state.ringTimer);
            state.ringTimer = null;
        }
        flashTitleStop();
    }

    function currentAjaxSecurity() {
        return {
            security: cfg.security || '',
            nonce: cfg.vmo_nonce || cfg.security || ''
        };
    }

    async function ajaxPost(action, payload) {
        const body = new URLSearchParams();
        body.set('action', actionAliases[action] || action);

        const security = currentAjaxSecurity();
        if (security.security) {
            body.set('security', security.security);
        }
        if (security.nonce) {
            body.set('nonce', security.nonce);
        }
        if (security.nonce || security.security) {
            body.set('_ajax_nonce', security.nonce || security.security);
        }

        Object.keys(payload || {}).forEach(function(key) {
            const value = payload[key];
            if (typeof value !== 'undefined' && value !== null) {
                body.set(key, String(value));
            }
        });

        const res = await fetch(cfg.ajaxurl, {
            method: 'POST',
            credentials: 'same-origin',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
            },
            body: body.toString()
        });

        let json = null;
        try {
            json = await res.json();
        } catch (e) {
            return {
                success: false,
                message: 'Invalid server response',
                data: {}
            };
        }

        return {
            success: !!json.success,
            message: (json.data && json.data.message) || json.message || '',
            data: json.data || {}
        };
    }

    function setCurrentCall(call, mode, statusText) {
        state.currentCall = call ? Object.assign({}, call) : null;
        state.currentMode = mode || 'idle';
        state.currentConference = call && call.conference_name ? call.conference_name : '';
        if (state.currentCall) {
            if (mode === 'listen' || mode === 'join') {
                clearDismissedIncoming(state.currentCall.call_sid);
            }
            state.currentCall.statusText = statusText || state.currentCall.statusText || '';
        }
        renderPanel();
    }

    function resetCurrentCall() {
        state.currentCall = null;
        state.currentMode = 'idle';
        state.currentConference = '';
        if (!state.browserConnection) {
            stopRinging();
        }
        renderPanel();
    }

    function attachDeviceListeners(device) {
        device.on('registered', function() {
            state.twilioReady = true;
            log('Device registered for incoming calls.');
        });

        device.on('error', function(err) {
            console.error('[VMO Phone Bridge] Twilio device error:', err);
        });

        device.on('incoming', function(call) {
            const fromNumber = (call && call.parameters && call.parameters.From) ? call.parameters.From : 'Unknown';
            log('Twilio Device incoming call from:', fromNumber);
            state.pendingIncomingConn = call;
            if (!state.currentCall || !state.currentCall.call_sid) {
                setCurrentCall({
                    call_sid: '',
                    from_number: fromNumber,
                    conference_name: '',
                    status: 'ringing',
                    statusText: 'Incoming call detected. Waiting for live call details…'
                }, 'incoming');
            }
            startRinging(fromNumber);

            call.on('cancel', function() {
                state.pendingIncomingConn = null;
                if (!state.currentCall || !state.currentCall.call_sid) {
                    resetCurrentCall();
                }
            });
            call.on('disconnect', function() {
                state.pendingIncomingConn = null;
            });
            call.on('reject', function() {
                state.pendingIncomingConn = null;
            });
        });
    }

    function createTwilioDevice(token) {
        if (!window.Twilio || !window.Twilio.Device) {
            return null;
        }
        const device = new window.Twilio.Device(token, {
            codecPreferences: ['opus', 'pcmu'],
            logLevel: 'warn',
            disableAudioContextSounds: true,
            enableImplicitPermissions: false,
            closeProtection: true
        });
        attachDeviceListeners(device);
        return device;
    }

    async function initTwilioDevice() {
        if (state.twilioReady && state.twilioDevice) {
            return true;
        }
        if (state.twilioInitPromise) {
            return state.twilioInitPromise;
        }

        state.twilioInitPromise = (async function() {
            log('Starting shared phone bridge device initialization...');

            if (!window.Twilio || !window.Twilio.Device) {
                console.warn('[VMO Phone Bridge] Twilio SDK unavailable; browser audio will stay disabled.');
                return false;
            }

            const tokenRes = await ajaxPost('vmo_twilio_browser_token', {});
            if (!tokenRes.success || !tokenRes.data || !tokenRes.data.token) {
                console.warn('[VMO Phone Bridge] Could not obtain browser token:', tokenRes.message || tokenRes.data);
                return false;
            }

            state.twilioDevice = createTwilioDevice(tokenRes.data.token);
            if (!state.twilioDevice) {
                return false;
            }

            try {
                await state.twilioDevice.register();
                state.twilioReady = true;
                return true;
            } catch (e) {
                state.twilioReady = false;
                console.error('[VMO Phone Bridge] Device registration failed:', e);
                return false;
            }
        })().finally(function() {
            state.twilioInitPromise = null;
        });

        return state.twilioInitPromise;
    }

    async function ensureTwilioReady() {
        if (state.twilioReady && state.twilioDevice) {
            return true;
        }
        return initTwilioDevice();
    }

    async function primeBrowserLiveAudio(options) {
        options = options || {};
        const actionLabel = options.actionLabel || 'connect to the live call';
        const required = options.required === true;

        if (state.browserLiveAudioPrimed) {
            return true;
        }

        if (!navigator.mediaDevices || typeof navigator.mediaDevices.getUserMedia !== 'function') {
            return true;
        }

        if (!state.browserLiveAudioPrimePromise) {
            state.browserLiveAudioPrimePromise = navigator.mediaDevices.getUserMedia({ audio: true })
                .then(function(stream) {
                    try {
                        stream.getTracks().forEach(function(track) { track.stop(); });
                    } catch (_) {}
                    state.browserLiveAudioPrimed = true;
                    return true;
                })
                .catch(function(err) {
                    console.warn('[VMO Phone Bridge] Browser live audio prime failed:', err);
                    return required ? false : true;
                })
                .finally(function() {
                    state.browserLiveAudioPrimePromise = null;
                });
        }

        const timeoutMs = Number.isFinite(Number(options.timeoutMs))
            ? Math.max(250, Number(options.timeoutMs))
            : (required ? 5000 : 900);

        return await new Promise(function(resolve) {
            let settled = false;
            const finish = function(value) {
                if (settled) {
                    return;
                }
                settled = true;
                resolve(value);
            };
            const timer = window.setTimeout(function() {
                if (settled) {
                    return;
                }
                console.warn('[VMO Phone Bridge] Browser live audio prime timed out; proceeding with ' + actionLabel + '.');
                finish(required ? false : true);
            }, timeoutMs);

            Promise.resolve(state.browserLiveAudioPrimePromise).then(function(value) {
                window.clearTimeout(timer);
                finish(value);
            }).catch(function() {
                window.clearTimeout(timer);
                finish(required ? false : true);
            });
        });
    }

    async function prepareBrowserLiveAudio(options) {
        options = options || {};
        const required = options.required === true;
        const actionLabel = options.actionLabel || 'connect to the live call';

        const primed = await primeBrowserLiveAudio({
            actionLabel: actionLabel,
            required: required
        });
        if (!primed && required) {
            notify('Browser audio permission is required to ' + actionLabel + '.', 'error');
            return false;
        }

        const ready = await ensureTwilioReady();
        if (!ready && required) {
            notify('Browser audio is unavailable on this page right now.', 'error');
            return false;
        }

        return !!ready;
    }

    async function endActiveCallEverywhere(reason, options) {
        options = options || {};
        if (state.endingCall) {
            return false;
        }

        const ids = currentTeardownIds();
        if (!ids.callSid && !ids.childSid) {
            stopBridgeListenSession();
            if (state.browserConnection && options.disconnectLocal !== false) {
                try { state.browserConnection.disconnect(); } catch (_) {}
            }
            try {
                await ajaxPost('vmo_end_call', {
                    call_sid: '',
                    child_sid: '',
                    force_active: '1',
                    reason: reason || 'browser_disconnect_lost_sid'
                });
                notify('Call end sent.', 'success');
            } catch (e) {
                console.error('[VMO Phone Bridge] Force end active call error:', e);
                notify('Browser audio was closed, but the server did not confirm call end.', 'warning');
            }
            state.browserConnection = null;
            state.isMuted = false;
            state.isOnHold = false;
            resetCurrentCall();
            return false;
        }

        state.endingCall = true;
        setButtonsDisabled(true);
        stopBridgeListenSession();
        releasePendingIncomingConn();

        const activeConnection = state.browserConnection;
        state.browserConnection = null;
        if (activeConnection && options.disconnectLocal !== false) {
            try { activeConnection.disconnect(); } catch (_) {}
        }

        try {
            const res = await ajaxPost('vmo_call_action', {
                action_type: 'end',
                call_sid: ids.callSid || '',
                child_sid: ids.childSid || '',
                conference_sid: ids.conferenceSid || '',
                via: 'browser',
                reason: reason || 'browser_disconnect'
            });

            if (!res.success) {
                await ajaxPost('vmo_end_call', {
                    call_sid: ids.callSid || '',
                    child_sid: ids.childSid || '',
                    force_active: '1',
                    reason: reason || 'browser_disconnect'
                });
            }

            notify('Call ended.', 'success');
        } catch (e) {
            console.error('[VMO Phone Bridge] End call error:', e);
            notify('Call end was sent, but the server response was not confirmed.', 'warning');
        } finally {
            state.isMuted = false;
            state.isOnHold = false;
            state.currentConference = '';
            state.endingCall = false;
            setButtonsDisabled(false);
            resetCurrentCall();
            try { refreshLiveCalls(); } catch (_) {}
        }

        return true;
    }

    function stopBridgeListenSession() {
        if (!state.bridgeListen) {
            return;
        }
        try {
            if (state.bridgeListen.socket) {
                state.bridgeListen.socket.close();
            }
        } catch (_) {}
        try {
            (state.bridgeListen.sources || []).forEach(function(source) {
                if (source && source.stop) {
                    source.stop();
                }
            });
        } catch (_) {}
        state.bridgeListen = null;
    }

    function decodeMulawSample(byteValue) {
        const muLawByte = (~byteValue) & 0xff;
        const sign = muLawByte & 0x80;
        const exponent = (muLawByte >> 4) & 0x07;
        const mantissa = muLawByte & 0x0f;
        const bias = 0x84;
        let sample = ((mantissa << 3) + bias) << exponent;
        sample = sign ? (bias - sample) : (sample - bias);
        return sample / 32768;
    }

    function base64ToBytes(base64Payload) {
        const binary = atob(base64Payload || '');
        const bytes = new Uint8Array(binary.length);
        for (let index = 0; index < binary.length; index += 1) {
            bytes[index] = binary.charCodeAt(index);
        }
        return bytes;
    }

    function extractBridgeMediaPayload(rawMessage) {
        if (!rawMessage || typeof rawMessage !== 'string') {
            return '';
        }
        try {
            const msg = JSON.parse(rawMessage);
            if (msg && msg.event === 'media' && msg.media && msg.media.payload) return msg.media.payload;
            if (msg && msg.type === 'media' && msg.payload) return msg.payload;
            if (msg && msg.payload) return msg.payload;
        } catch (_) {
            if (/^[A-Za-z0-9+/=]+$/.test(rawMessage)) return rawMessage;
        }
        return '';
    }

    async function startBridgeListenSession(activeCall, data) {
        stopBridgeListenSession();

        const AudioContextCtor = window.AudioContext || window.webkitAudioContext;
        if (!AudioContextCtor) {
            notify('This browser cannot play live call audio.', 'error');
            return false;
        }

        const audioContext = state.audioContext || new AudioContextCtor();
        state.audioContext = audioContext;
        if (audioContext.state === 'suspended') {
            try { await audioContext.resume(); } catch (_) {}
        }

        const bridgeState = {
            socket: null,
            nextPlayTime: audioContext.currentTime + 0.08,
            sources: []
        };
        state.bridgeListen = bridgeState;

        return await new Promise(function(resolve) {
            let settled = false;
            let opened = false;
            const settle = function(value) {
                if (settled) return;
                settled = true;
                resolve(value);
            };

            try {
                const socket = new WebSocket(data.listen_url);
                bridgeState.socket = socket;

                socket.onopen = function() {
                    opened = true;
                    stopRinging();
                    setCurrentCall(activeCall, 'listen', data.message || 'Listening to Premium realtime audio. You can take over at any time.');
                    notify(data.message || 'Listening to Premium realtime audio.', 'success');
                    settle(true);
                };

                socket.onmessage = function(event) {
                    const payload = extractBridgeMediaPayload(event.data);
                    if (!payload) return;

                    let bytes;
                    try { bytes = base64ToBytes(payload); } catch (_) { return; }
                    if (!bytes.length) return;

                    const buffer = audioContext.createBuffer(1, bytes.length, 8000);
                    const channel = buffer.getChannelData(0);
                    for (let index = 0; index < bytes.length; index += 1) {
                        channel[index] = decodeMulawSample(bytes[index]);
                    }

                    const source = audioContext.createBufferSource();
                    source.buffer = buffer;
                    source.connect(audioContext.destination);
                    const playAt = Math.max(bridgeState.nextPlayTime, audioContext.currentTime + 0.02);
                    source.start(playAt);
                    bridgeState.nextPlayTime = playAt + buffer.duration;
                    bridgeState.sources.push(source);
                    source.onended = function() {
                        bridgeState.sources = bridgeState.sources.filter(function(item) { return item !== source; });
                    };
                };

                socket.onerror = function() {
                    if (!opened) {
                        notify('Premium live audio failed to connect.', 'error');
                        stopBridgeListenSession();
                        settle(false);
                    }
                };

                socket.onclose = function() {
                    if (state.bridgeListen && state.bridgeListen.socket === socket) {
                        try {
                            (state.bridgeListen.sources || []).forEach(function(source) {
                                if (source && source.stop) {
                                    source.stop();
                                }
                            });
                        } catch (_) {}
                        state.bridgeListen = null;
                        if (state.currentCall) {
                            state.currentCall.statusText = 'Premium live audio ended. The call may still be active.';
                        }
                        renderPanel();
                    }
                    if (!settled) {
                        notify('Premium live audio is no longer available for this call.', opened ? 'info' : 'error');
                        settle(false);
                    } else if (opened) {
                        notify('Premium live audio ended.', 'info');
                    }
                };
            } catch (_) {
                notify('Premium live audio could not start.', 'error');
                stopBridgeListenSession();
                settle(false);
            }
        });
    }

    async function handleHold() {
        if (!state.currentCall || !state.currentCall.call_sid) {
            notify('No active call to hold.', 'warning');
            return;
        }
        setButtonsDisabled(true);
        try {
            var actionType = state.isOnHold ? 'unhold' : 'hold';
            var res = await ajaxPost('vmo_call_action', {
                action_type: actionType,
                call_sid: state.currentCall.call_sid,
                conference_sid: state.currentConference || state.currentCall.conference_name || '',
                via: 'browser'
            });
            if (res.success) {
                state.isOnHold = !state.isOnHold;
                if (state.currentCall) {
                    state.currentCall.statusText = state.isOnHold
                        ? 'Caller is on hold.'
                        : 'Caller resumed from hold.';
                }
                notify(state.isOnHold ? 'Caller placed on hold.' : 'Caller resumed.', 'info');
            } else {
                notify(res.message || 'Hold action failed.', 'error');
            }
        } finally {
            setButtonsDisabled(false);
            renderPanel();
        }
    }

    function handleMute() {
        if (!state.browserConnection) {
            notify('No browser audio connection to mute.', 'warning');
            return;
        }
        try {
            state.isMuted = !state.isMuted;
            state.browserConnection.mute(state.isMuted);
            if (state.currentCall) {
                state.currentCall.statusText = state.isMuted
                    ? 'You are muted. The caller cannot hear you.'
                    : 'Unmuted. You are live on the call.';
            }
            notify(state.isMuted ? 'Microphone muted.' : 'Microphone unmuted.', 'info');
        } catch (e) {
            console.error('[VMO Phone Bridge] Mute error:', e);
            notify('Failed to toggle mute.', 'error');
            state.isMuted = false;
        }
        renderPanel();
    }

    async function browserJoinConference(conferenceName, mode) {
        if (!conferenceName) {
            notify('No live conference is available for this call.', 'warning');
            return false;
        }

        stopBridgeListenSession();

        const ready = await ensureTwilioReady();
        if (!ready || !state.twilioDevice) {
            notify('Browser audio is unavailable on this page right now.', 'error');
            return false;
        }

        if (state.browserConnection) {
            try {
                state.browserConnection.disconnect();
            } catch (_) {}
            state.browserConnection = null;
        }

        try {
            const call = await state.twilioDevice.connect({
                params: {
                    conference: conferenceName,
                    mode: mode || 'join'
                }
            });
            state.browserConnection = call;
            state.currentConference = conferenceName;

            call.on('accept', function() {
                state.currentMode = (mode === 'listen') ? 'listen' : 'join';
                if (state.currentCall) {
                    state.currentCall.statusText = (mode === 'listen')
                        ? 'Listening live. You can take over at any time.'
                        : 'Browser audio is connected. You are now on the call.';
                }
                stopRinging();
                renderPanel();
            });

            call.on('disconnect', function() {
                const shouldEndServerCall = !state.endingCall && state.currentCall && state.currentCall.call_sid;
                state.browserConnection = null;
                if (shouldEndServerCall) {
                    endActiveCallEverywhere('browser_disconnect', { disconnectLocal: false });
                    return;
                }
                if (state.currentCall) {
                    state.currentMode = 'idle';
                    state.currentCall.statusText = 'Browser audio disconnected.';
                }
                renderPanel();
            });

            call.on('error', function(err) {
                console.error('[VMO Phone Bridge] Browser conference error:', err);
                notify('Browser audio error: ' + ((err && err.message) ? err.message : 'Unknown error'), 'error');
            });

            return true;
        } catch (e) {
            console.error('[VMO Phone Bridge] Failed to join browser conference:', e);
            notify('Failed to connect browser audio.', 'error');
            return false;
        }
    }

    async function refreshLiveCalls() {
        const res = await ajaxPost('vmo_get_live_calls', {});
        if (!res.success) {
            return [];
        }
        const data = res.data || {};
        const calls = Array.isArray(data.calls) ? data.calls.slice() : [];
        if (data.ring_now && data.ring_now.call_sid) {
            const exists = calls.some(function(call) {
                return call.call_sid === data.ring_now.call_sid;
            });
            if (!exists) {
                // Find matching call in data.calls to inherit owner_alert_ready
                var matchedCall = null;
                if (Array.isArray(data.calls)) {
                    matchedCall = data.calls.find(function(c) {
                        return c.call_sid === data.ring_now.call_sid;
                    });
                }
                calls.unshift({
                    call_sid: data.ring_now.call_sid,
                    from_number: data.ring_now.from || 'Unknown',
                    direction: 'inbound',
                    status: 'ringing',
                    conference_name: 'vmo_call_' + data.ring_now.call_sid,
                    owner_alert_ready: matchedCall ? matchedCall.owner_alert_ready : true
                });
            }
        }
        return calls;
    }

    async function resolveCurrentCall() {
        const calls = await refreshLiveCalls();
        if (!calls.length) {
            return null;
        }
        if (state.currentCall && state.currentCall.call_sid) {
            const same = calls.find(function(call) {
                return call.call_sid === state.currentCall.call_sid;
            });
            if (same) {
                return same;
            }
        }
        return calls.find(function(call) {
            return String(call.direction || '').toLowerCase() === 'inbound';
        }) || calls[0];
    }

    function getPendingIncomingChildSid() {
        return (state.pendingIncomingConn && state.pendingIncomingConn.parameters && state.pendingIncomingConn.parameters.CallSid)
            ? String(state.pendingIncomingConn.parameters.CallSid || '')
            : '';
    }

    function shouldRetryIncomingAction(res) {
        const message = String((res && res.message) || '').toLowerCase();
        return message.indexOf('could not resolve the live call') !== -1
            || message.indexOf('missing call sid') !== -1
            || message.indexOf('no active incoming call') !== -1;
    }

    function waitForRetry(ms) {
        return new Promise(function(resolve) {
            window.setTimeout(resolve, ms);
        });
    }

    function releasePendingIncomingConn() {
        if (!state.pendingIncomingConn) {
            return;
        }
        try {
            state.pendingIncomingConn.reject();
        } catch (_) {}
        state.pendingIncomingConn = null;
    }

    async function requestIncomingCallAction(actionType, explicitCall) {
        let targetCall = explicitCall || null;
        let lastResult = null;

        for (let attempt = 0; attempt < 3; attempt += 1) {
            targetCall = await resolveCurrentCall();
            const childSid = getPendingIncomingChildSid() || (targetCall && targetCall.browser_call_sid ? String(targetCall.browser_call_sid || '') : '');

            if (!targetCall || (!targetCall.call_sid && !childSid)) {
                lastResult = {
                    success: false,
                    message: 'Could not resolve the live call to control.',
                    data: {}
                };
            } else {
                lastResult = await ajaxPost('vmo_call_action', {
                    action_type: actionType,
                    call_sid: targetCall.call_sid || '',
                    conference_sid: targetCall.conference_sid || targetCall.conference_name || state.currentConference || '',
                    via: 'browser',
                    child_sid: childSid || ''
                });

                if (lastResult && lastResult.success) {
                    if (childSid && !targetCall.browser_call_sid) {
                        targetCall = Object.assign({}, targetCall, {
                            browser_call_sid: childSid
                        });
                    }

                    return {
                        call: targetCall,
                        response: lastResult
                    };
                }
            }

            if (attempt >= 2 || !shouldRetryIncomingAction(lastResult)) {
                break;
            }

            await waitForRetry(250 * (attempt + 1));
        }

        return {
            call: targetCall,
            response: lastResult || {
                success: false,
                message: 'Could not resolve the live call to control.',
                data: {}
            }
        };
    }

    async function handleListen() {
        setButtonsDisabled(true);
        try {
            const call = await resolveCurrentCall();
            if (!call || !call.call_sid) {
                notify('No active incoming call is available to listen to.', 'warning');
                return;
            }

            setCurrentCall(call, 'incoming', 'Preparing listen mode…');
            const listenAction = await requestIncomingCallAction('listen', call);
            const res = listenAction.response;
            const activeCall = listenAction.call || call;
            if (!res.success) {
                notify(res.message || 'Listen failed.', 'error');
                return;
            }

            const data = res.data || {};
            releasePendingIncomingConn();

            if (data.mode === 'bridge_ws' && data.listen_url) {
                await startBridgeListenSession(activeCall, data);
                return;
            }

            if (data.mode === 'transcript') {
                setCurrentCall(activeCall, 'incoming', data.message || 'Live listen is unavailable for this call.');
                notify(data.message || 'Live listen is unavailable for this call.', 'error');
                return;
            }
            if (data.mode === 'realtime_monitor') {
                stopRinging();
                releasePendingIncomingConn();
                const msg = data.message || 'AI is attending the call.';
                setCurrentCall(activeCall, 'listen', msg);
                notify(msg, 'info');
                return;
            }

            const conferenceName = data.conference_name || activeCall.conference_name || state.currentConference || '';
            if (conferenceName) {
                const audioReady = await prepareBrowserLiveAudio({
                    required: true,
                    actionLabel: 'listen to the live call'
                });
                if (!audioReady) {
                    return;
                }
                const joined = await browserJoinConference(conferenceName, 'listen');
                if (!joined) {
                    return;
                }
            }

            stopRinging();
            setCurrentCall(Object.assign({}, activeCall, { conference_name: conferenceName }), 'listen', data.message || 'Listening live. You can take over at any time.');
        } finally {
            setButtonsDisabled(false);
        }
    }

    async function handleTakeOver() {
        setButtonsDisabled(true);
        try {
            const call = await resolveCurrentCall();
            if (!call || !call.call_sid) {
                notify('No active incoming call is available to take over.', 'warning');
                return;
            }

            setCurrentCall(call, 'incoming', 'Connecting you to the caller…');
            const audioReady = await prepareBrowserLiveAudio({
                required: true,
                actionLabel: 'take over the live call'
            });
            if (!audioReady) {
                return;
            }
            const takeoverAction = await requestIncomingCallAction('join', call);
            const res = takeoverAction.response;
            const activeCall = takeoverAction.call || call;
            if (!res.success) {
                notify(res.message || 'Take over failed.', 'error');
                return;
            }

            const data = res.data || {};
            releasePendingIncomingConn();
            const conferenceName = data.conference_name || activeCall.conference_name || state.currentConference || '';
            if (conferenceName) {
                stopBridgeListenSession();
                const joined = await browserJoinConference(conferenceName, 'join');
                if (!joined) {
                    return;
                }
            }

            stopRinging();
            setCurrentCall(Object.assign({}, activeCall, { conference_name: conferenceName }), 'join', data.message || 'Browser audio connected. You are now on the call.');
        } finally {
            setButtonsDisabled(false);
        }
    }

    function syncCurrentCallFromPoll(targetCall) {
        if (!targetCall) {
            if (!state.pendingIncomingConn) {
                resetCurrentCall();
            }
            return;
        }

        const incoming = String(targetCall.direction || '').toLowerCase() === 'inbound';
        if (!incoming) {
            return;
        }

        // Scenario C: Do not ring during IVR department selection.
        // owner_alert_ready is false while the caller is navigating extensions.
        var alertReady = (typeof targetCall.owner_alert_ready !== 'undefined')
            ? !!targetCall.owner_alert_ready
            : true;
        if (!alertReady && state.currentMode !== 'listen' && state.currentMode !== 'join') {
            return;
        }

        if (isDismissedIncoming(targetCall) && state.currentMode !== 'listen' && state.currentMode !== 'join') {
            return;
        }

        const isNewSid = targetCall.call_sid && targetCall.call_sid !== state.lastRingSid;
        const statusText = state.currentCall && state.currentCall.statusText ? state.currentCall.statusText : 'Take over or listen live while AI handles the caller.';

        setCurrentCall(targetCall, state.currentMode === 'join' ? 'join' : (state.currentMode === 'listen' ? 'listen' : 'incoming'), statusText);

        if (isNewSid && alertReady) {
            state.lastRingSid = targetCall.call_sid;
            startRinging(targetCall.from_number || 'Unknown');
        }
    }

    async function pollLoop() {
        if (state.activePoll) {
            return;
        }
        state.activePoll = true;
        try {
            const calls = await refreshLiveCalls();
            const inboundCalls = calls.filter(function(call) {
                return String(call.direction || '').toLowerCase() === 'inbound';
            });

            if (state.currentCall && state.currentCall.call_sid) {
                const same = inboundCalls.find(function(call) {
                    return call.call_sid === state.currentCall.call_sid;
                });
                if (same) {
                    same.statusText = state.currentCall.statusText || '';
                    setCurrentCall(same, state.currentMode, same.statusText);
                    if (state.currentMode === 'join' || state.currentMode === 'listen') {
                        stopRinging();
                    }
                    return;
                }
            }

            if (inboundCalls.length) {
                syncCurrentCallFromPoll(inboundCalls[0]);
                return;
            }

            if (!state.pendingIncomingConn) {
                resetCurrentCall();
            }
        } catch (e) {
            console.error('[VMO Phone Bridge] Live-call polling error:', e);
        } finally {
            state.activePoll = false;
        }
    }

    function startPolling() {
        if (state.pollTimer) {
            return;
        }
        pollLoop();
        state.pollTimer = window.setInterval(pollLoop, 3000);
    }

    function init() {
        createPanel();
        startPolling();
        window.addEventListener('beforeunload', function() {
            if (state.pollTimer) {
                window.clearInterval(state.pollTimer);
            }
        });
        log('Shared incoming-call bridge started on page:', cfg.page || '(unknown)');
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})(window, document);
