import { SIPClient } from '@/lib/sip-client';
import type { SIPConfig, ConnectionStatus, CallState } from '@/types/sip';

// Singleton SIP client — survives React StrictMode remounts
let sipClient: SIPClient | null = null;
let connected = false;
let outboundPending = false;
let outboundActive = false;
let activeAgentId: string | null = null;

type StateUpdater = {
    setConnectionStatus: (status: ConnectionStatus) => void;
    setCallState: (state: CallState) => void;
    setCallerNumber: (number: string | null) => void;
    setCallUcid: (ucid: string | null) => void;
    setIsMuted: (muted: boolean) => void;
    setIsOnHold: (onHold: boolean) => void;
};

let stateUpdater: StateUpdater | null = null;

export function registerSipStateUpdater(updater: StateUpdater) {
    stateUpdater = updater;
}

export function setOutboundPending(pending: boolean) {
    outboundPending = pending;
}

export function isOutboundPending(): boolean {
    return outboundPending;
}

export function connectSip(config: SIPConfig): void {
    if (connected || sipClient?.isRegistered() || sipClient?.isConnected()) {
        return;
    }

    if (!config.wsServer || !config.uri) {
        console.warn('SIP config incomplete — wsServer and uri required');
        return;
    }

    if (sipClient) {
        sipClient.disconnect();
    }

    // Resolve agent identity for logging
    try {
        const agentCfg = JSON.parse(localStorage.getItem('helix_agent_config') ?? '{}');
        activeAgentId = agentCfg.ozonetelAgentId ?? null;
        const ext = config.uri?.match(/sip:(\d+)@/)?.[1] ?? 'unknown';
        console.log(`[SIP] Connecting agent=${activeAgentId} ext=${ext} ws=${config.wsServer}`);
    } catch {
        console.log(`[SIP] Connecting uri=${config.uri}`);
    }

    connected = true;
    stateUpdater?.setConnectionStatus('connecting');

    sipClient = new SIPClient(
        config,
        (status) => stateUpdater?.setConnectionStatus(status),
        (state, number, ucid) => {
            // Auto-answer SIP when it's a bridge from our outbound call
            if (state === 'ringing-in' && outboundPending) {
                outboundPending = false;
                outboundActive = true;
                console.log('[SIP-MGR] Outbound bridge detected — auto-answering');
                setTimeout(() => {
                    sipClient?.answer();
                    setTimeout(() => stateUpdater?.setCallState('active'), 300);
                }, 500);
                if (ucid) stateUpdater?.setCallUcid(ucid);
                return;
            }

            console.log(`[SIP] ${activeAgentId} | state=${state} | caller=${number ?? 'none'} | ucid=${ucid ?? 'none'} | outbound=${outboundActive}`);

            stateUpdater?.setCallState(state);
            if (!outboundActive && number !== undefined) {
                stateUpdater?.setCallerNumber(number ?? null);
            }

            if (ucid) stateUpdater?.setCallUcid(ucid);

            if (state === 'ended' || state === 'failed') {
                // Reset both the SIP track AND the Recoil state — otherwise the
                // UI icon + toggle-mute branch logic stay "muted" and the next
                // call opens in a confusing half-muted state.
                sipClient?.unmute();
                sipClient?.unhold();
                stateUpdater?.setIsMuted(false);
                stateUpdater?.setIsOnHold(false);
                outboundActive = false;
                outboundPending = false;
            }
        },
    );

    sipClient.connect();
}

export function disconnectSip(force = false, reason = 'unspecified'): void {
    // Guard: don't disconnect SIP during an active or pending call
    // unless explicitly forced (e.g., logout, page unload).
    // This prevents React re-render cycles from killing the
    // SIP WebSocket mid-dial.
    if (!force && (outboundPending || outboundActive)) {
        console.log(`[SIP-MGR] Disconnect blocked — call in progress (reason=${reason})`);
        return;
    }
    console.log(`[SIP] Disconnecting agent=${activeAgentId} reason=${reason}` + (force ? ' (forced)' : ''));
    sipClient?.disconnect();
    sipClient = null;
    connected = false;
    outboundPending = false;
    outboundActive = false;
    activeAgentId = null;
    stateUpdater?.setConnectionStatus('disconnected');
    stateUpdater?.setCallUcid(null);
}

export function getSipClient(): SIPClient | null {
    return sipClient;
}
