import { useEffect, useCallback, type PropsWithChildren } from 'react';
import { useAtom, useSetAtom } from 'jotai';
import {
    sipConnectionStatusAtom,
    sipCallStateAtom,
    sipCallerNumberAtom,
    sipIsMutedAtom,
    sipIsOnHoldAtom,
    sipCallDurationAtom,
    sipCallStartTimeAtom,
    sipCallUcidAtom,
} from '@/state/sip-state';
import { registerSipStateUpdater, connectSip, disconnectSip, getSipClient, setOutboundPending } from '@/state/sip-manager';
import { apiClient } from '@/lib/api-client';
import type { SIPConfig } from '@/types/sip';

// SIP config comes exclusively from the Agent entity (stored on login).
// No env var fallback — users without an Agent entity don't connect SIP.
const getSipConfig = (): SIPConfig | null => {
    try {
        const stored = localStorage.getItem('helix_agent_config');
        if (stored) {
            const config = JSON.parse(stored);
            if (config.sipUri && config.sipWsServer) {
                return {
                    displayName: 'Helix Agent',
                    uri: config.sipUri,
                    password: config.sipPassword,
                    wsServer: config.sipWsServer,
                    stunServers: 'stun:stun.l.google.com:19302',
                };
            }
        }
    } catch {}
    return null;
};

export const SipProvider = ({ children }: PropsWithChildren) => {
    const [, setConnectionStatus] = useAtom(sipConnectionStatusAtom);
    const [callState, setCallState] = useAtom(sipCallStateAtom);
    const setCallerNumber = useSetAtom(sipCallerNumberAtom);
    const setCallUcid = useSetAtom(sipCallUcidAtom);
    const setCallDuration = useSetAtom(sipCallDurationAtom);
    const setCallStartTime = useSetAtom(sipCallStartTimeAtom);

    // Register Jotai setters so the singleton SIP manager can update atoms
    useEffect(() => {
        registerSipStateUpdater({
            setConnectionStatus,
            setCallState,
            setCallerNumber,
            setCallUcid,
        });
    }, [setConnectionStatus, setCallState, setCallerNumber, setCallUcid]);

    // Auto-connect SIP on mount — only if Agent entity has SIP config
    useEffect(() => {
        const config = getSipConfig();
        if (config) {
            connectSip(config);
        } else {
            console.log('[SIP] No agent SIP config — skipping connection');
        }
    }, []);

    // Call duration timer
    useEffect(() => {
        if (callState === 'active') {
            const start = new Date();
            setCallStartTime(start);
            const interval = window.setInterval(() => {
                setCallDuration(Math.floor((Date.now() - start.getTime()) / 1000));
            }, 1000);
            return () => clearInterval(interval);
        }
        setCallDuration(0);
        setCallStartTime(null);
    }, [callState, setCallDuration, setCallStartTime]);

    // Ringtone on incoming call
    useEffect(() => {
        if (callState === 'ringing-in') {
            import('@/lib/ringtone').then(({ startRingtone }) => startRingtone());
        } else {
            import('@/lib/ringtone').then(({ stopRingtone }) => stopRingtone());
        }
    }, [callState]);

    // No auto-reset — the ActiveCallCard handles post-call flow (disposition → appointment → done)
    // and resets to idle via the "Back to Worklist" button

    // Cleanup on unmount + page unload
    useEffect(() => {
        const handleUnload = () => disconnectSip();
        window.addEventListener('beforeunload', handleUnload);
        return () => {
            window.removeEventListener('beforeunload', handleUnload);
            disconnectSip();
        };
    }, []);

    return <>{children}</>;
};

// Hook for components to access SIP actions + state
export const useSip = () => {
    const [connectionStatus] = useAtom(sipConnectionStatusAtom);
    const [callState, setCallState] = useAtom(sipCallStateAtom);
    const [callerNumber, setCallerNumber] = useAtom(sipCallerNumberAtom);
    const [callUcid, setCallUcid] = useAtom(sipCallUcidAtom);
    const [isMuted, setIsMuted] = useAtom(sipIsMutedAtom);
    const [isOnHold, setIsOnHold] = useAtom(sipIsOnHoldAtom);
    const [callDuration] = useAtom(sipCallDurationAtom);

    const makeCall = useCallback((phoneNumber: string) => {
        getSipClient()?.call(phoneNumber);
        setCallerNumber(phoneNumber);
    }, [setCallerNumber]);

    // Ozonetel outbound dial — single path for all outbound calls
    const dialOutbound = useCallback(async (phoneNumber: string): Promise<void> => {
        console.log(`[DIAL] Outbound dial started: phone=${phoneNumber}`);
        setCallState('ringing-out');
        setCallerNumber(phoneNumber);
        setOutboundPending(true);
        const safetyTimeout = setTimeout(() => {
            console.warn('[DIAL] Safety timeout fired (30s) — clearing outboundPending');
            setOutboundPending(false);
        }, 30000);

        try {
            const result = await apiClient.post<{ status: string; ucid?: string }>('/api/ozonetel/dial', { phoneNumber });
            console.log('[DIAL] Dial API response:', result);
            clearTimeout(safetyTimeout);
            // Store UCID from dial response — SIP bridge doesn't carry X-UCID for outbound
            if (result?.ucid) {
                console.log(`[DIAL] Storing UCID from dial response: ${result.ucid}`);
                setCallUcid(result.ucid);
            }
        } catch (err) {
            console.error('[DIAL] Dial API failed:', err);
            clearTimeout(safetyTimeout);
            setOutboundPending(false);
            setCallState('idle');
            setCallerNumber(null);
            throw new Error('Dial failed');
        }
    }, [setCallState, setCallerNumber, setCallUcid]);

    const answer = useCallback(() => getSipClient()?.answer(), []);
    const reject = useCallback(() => getSipClient()?.reject(), []);
    const hangup = useCallback(() => getSipClient()?.hangup(), []);

    const toggleMute = useCallback(() => {
        if (isMuted) {
            getSipClient()?.unmute();
        } else {
            getSipClient()?.mute();
        }
        setIsMuted(!isMuted);
    }, [isMuted, setIsMuted]);

    const toggleHold = useCallback(() => {
        if (isOnHold) {
            getSipClient()?.unhold();
        } else {
            getSipClient()?.hold();
        }
        setIsOnHold(!isOnHold);
    }, [isOnHold, setIsOnHold]);

    return {
        connectionStatus,
        callState,
        callerNumber,
        callUcid,
        isMuted,
        isOnHold,
        callDuration,
        isRegistered: connectionStatus === 'registered',
        isInCall: ['ringing-in', 'ringing-out', 'active'].includes(callState),
        ozonetelStatus: 'logged-in' as const,
        ozonetelError: null as string | null,
        connect: () => { const c = getSipConfig(); if (c) connectSip(c); },
        disconnect: disconnectSip,
        makeCall,
        dialOutbound,
        answer,
        reject,
        hangup,
        toggleMute,
        toggleHold,
    };
};
