import JsSIP from 'jssip';
type RTCSession = any;

// Lightweight SIP client for supervisor barge sessions.
// Separate from the agent's sip-client.ts — different lifecycle.
// Modeled on Ozonetel's kSip utility (CA-Admin/.../utils/ksip.tsx).
//
// DTMF mode mapping (from Ozonetel CA-Admin BargeinDrawerSip.tsx):
//   "4" → Listen (supervisor hears all, nobody hears supervisor)
//   "5" → Whisper/Training (agent hears supervisor, patient doesn't)
//   "6" → Barge (both hear supervisor)

type EventCallback = (...args: any[]) => void;
type SupervisorSipEvent =
    | 'registered'
    | 'registrationFailed'
    | 'callReceived'
    | 'callConnected'
    | 'callEnded'
    | 'callFailed';

type SupervisorSipConfig = {
    domain: string;
    port: string;
    number: string;
    password: string;
};

class SupervisorSipClient {
    private ua: JsSIP.UA | null = null;
    private session: RTCSession | null = null;
    private listeners = new Map<string, Set<EventCallback>>();
    private audioElement: HTMLAudioElement | null = null;

    init(config: SupervisorSipConfig): void {
        this.cleanup();

        // Hidden audio element for remote call audio
        this.audioElement = document.createElement('audio');
        this.audioElement.id = 'supervisor-remote-audio';
        this.audioElement.autoplay = true;
        this.audioElement.setAttribute('playsinline', '');
        document.body.appendChild(this.audioElement);

        const socketUrl = `wss://${config.domain}:${config.port}`;
        const socket = new JsSIP.WebSocketInterface(socketUrl);

        this.ua = new JsSIP.UA({
            sockets: [socket],
            uri: `sip:${config.number}@${config.domain}`,
            password: config.password,
            registrar_server: `sip:${config.domain}`,
            authorization_user: config.number,
            session_timers: false,
            register: false,
        });

        this.ua.on('registered', () => {
            console.log('[SupervisorSIP] Registered');
            this.emit('registered');
        });

        this.ua.on('registrationFailed', (e: any) => {
            console.error('[SupervisorSIP] Registration failed:', e?.cause);
            this.emit('registrationFailed', e?.cause);
        });

        this.ua.on('newRTCSession', (data: any) => {
            const rtcSession = data.session as RTCSession;
            if (rtcSession.direction !== 'incoming') return;

            console.log('[SupervisorSIP] Incoming call — auto-answering');
            this.session = rtcSession;
            this.emit('callReceived');

            rtcSession.on('accepted', () => {
                console.log('[SupervisorSIP] Call accepted');
                this.emit('callConnected');
            });

            rtcSession.on('confirmed', () => {
                // Attach remote audio stream
                const connection = rtcSession.connection;
                if (connection && this.audioElement) {
                    // Modern browsers: track event
                    connection.addEventListener('track', (event: RTCTrackEvent) => {
                        if (event.streams[0] && this.audioElement) {
                            this.audioElement.srcObject = event.streams[0];
                        }
                    });
                    // Fallback: getRemoteStreams (older browsers/JsSIP versions)
                    const remoteStreams = (connection as any).getRemoteStreams?.();
                    if (remoteStreams?.[0] && this.audioElement) {
                        this.audioElement.srcObject = remoteStreams[0];
                    }
                }
            });

            rtcSession.on('ended', () => {
                console.log('[SupervisorSIP] Call ended');
                this.session = null;
                this.emit('callEnded');
            });

            rtcSession.on('failed', (e: any) => {
                console.error('[SupervisorSIP] Call failed:', e?.cause);
                this.session = null;
                this.emit('callFailed', e?.cause);
            });

            // Auto-answer with audio
            rtcSession.answer({
                mediaConstraints: { audio: true, video: false },
            });
        });

        this.ua.start();
    }

    register(): void {
        this.ua?.register();
    }

    isRegistered(): boolean {
        return this.ua?.isRegistered() ?? false;
    }

    isCallActive(): boolean {
        return this.session?.isEstablished() ?? false;
    }

    sendDTMF(digit: string): void {
        if (!this.session?.isEstablished()) {
            console.warn('[SupervisorSIP] Cannot send DTMF — no active session');
            return;
        }
        console.log(`[SupervisorSIP] Sending DTMF: ${digit}`);
        this.session.sendDTMF(digit, {
            duration: 160,
            interToneGap: 1200,
        });
    }

    hangup(): void {
        if (this.session) {
            try {
                this.session.terminate();
            } catch {
                // Session may already be ended
            }
            this.session = null;
        }
    }

    close(): void {
        this.hangup();
        if (this.ua) {
            try {
                this.ua.unregister({ all: true });
                this.ua.stop();
            } catch {
                // UA may already be stopped
            }
            this.ua = null;
        }
        this.cleanup();
        this.listeners.clear();
    }

    on(event: SupervisorSipEvent, callback: EventCallback): void {
        if (!this.listeners.has(event)) {
            this.listeners.set(event, new Set());
        }
        this.listeners.get(event)!.add(callback);
    }

    off(event: SupervisorSipEvent, callback: EventCallback): void {
        this.listeners.get(event)?.delete(callback);
    }

    private emit(event: string, ...args: any[]): void {
        this.listeners.get(event)?.forEach(cb => {
            try { cb(...args); } catch (e) { console.error(`[SupervisorSIP] Event error [${event}]:`, e); }
        });
    }

    private cleanup(): void {
        if (this.audioElement) {
            this.audioElement.srcObject = null;
            this.audioElement.remove();
            this.audioElement = null;
        }
    }
}

export const supervisorSip = new SupervisorSipClient();
